home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1995 May / cd Ware (Juegos) Epimundo.iso / DOS / C / PSK.ZIP / PSK.DOC < prev    next >
Encoding:
Text File  |  1993-05-23  |  108.3 KB  |  3,073 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.                                 PSK User Manual
  59.  
  60.  
  61.  
  62.                                   Version 1.3
  63.  
  64.  
  65.  
  66.                     Copyright (C) 1993, Geoff Friesen B.Sc.
  67.  
  68.                              All rights reserved.
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.                                -1Table of Contents-0
  131.  
  132.  
  133.  
  134.  
  135.  
  136.     Introduction........................................................ 3
  137.  
  138.     Chapter  1 ■ Character Classification and Conversion................ 4
  139.  
  140.     Chapter  2 ■ Critical Error Handler................................. 5
  141.  
  142.     Chapter  3 ■ Data Entry............................................. 8
  143.  
  144.     Chapter  4 ■ Dates..................................................11
  145.  
  146.     Chapter  5 ■ Dialog Box.............................................12
  147.  
  148.     Chapter  6 ■ Event Handling.........................................14
  149.  
  150.     Chapter  7 ■ File and Directory.....................................17
  151.  
  152.     Chapter  8 ■ Game Support...........................................19
  153.  
  154.     Chapter  9 ■ Keyboard and Context-Sensitive Help....................21
  155.  
  156.     Chapter 10 ■ Macros.................................................23
  157.  
  158.     Chapter 11 ■ Message Boxes..........................................24
  159.  
  160.     Chapter 12 ■ Mouse Support..........................................25
  161.  
  162.     Chapter 13 ■ Printing...............................................29
  163.  
  164.     Chapter 14 ■ Security...............................................31
  165.  
  166.     Chapter 15 ■ String Tools...........................................33
  167.  
  168.     Chapter 16 ■ System Query...........................................35
  169.  
  170.     Chapter 17 ■ Video..................................................36
  171.  
  172.     Appendix A ■ Dealing with Errors....................................42
  173.  
  174.     Appendix B ■ DBASE III+ File Format.................................43
  175.  
  176.     Appendix C ■ MAKEDRV................................................45
  177.  
  178.     Appendix D ■ Sample Programs........................................46
  179.  
  180.     Appendix E ■ Installation...........................................48
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.                                  -1Introduction-0
  255.  
  256.  
  257.  
  258.  
  259.  
  260.     Welcome  to Programmer's  Survival  Kit  (PSK).  PSK  is a  LARGE-model
  261.  
  262.     library  of C  functions designed  to help  you complete  a variety  of
  263.  
  264.     programming  projects quickly  and  efficiently.  Although Borland  C++
  265.  
  266.     3.1 was used to create  this library, previous versions of  Borland C++
  267.  
  268.     can be used  to develop programs  with PSK. Turbo  C and Turbo  C++ can
  269.  
  270.     probably be used as well.
  271.  
  272.  
  273.  
  274.     PSK is  shareware. Registration  information can  be found  in the file
  275.  
  276.     PSK.REG.  One of  the benefits  to registering  your copy  is that  you
  277.  
  278.     will receive  all of  the source  code. You  can customize  PSK to meet
  279.  
  280.     your needs or port it to other compilers.
  281.  
  282.  
  283.  
  284.     Instructions  on how  to  install  PSK  can  be  found  in Appendix  E.
  285.  
  286.  
  287.  
  288.     Several example programs  have been written  to illustrate the  various
  289.  
  290.     functions in this  library. These programs  are documented in  Appendix
  291.  
  292.     D.
  293.  
  294.  
  295.  
  296.     PSK should  be used  to develop  programs that  run under  DOS 3.30  or
  297.  
  298.     higher. This  limitation stems  from the  fact that  the critical error
  299.  
  300.     handler uses a  DOS feature that  only became available  beginning with
  301.  
  302.     version 3.30.
  303.  
  304.  
  305.  
  306.     Version  1.3 differs  from  its  predecessor  as  follows.  The  string
  307.  
  308.     toolbox   has  been   expanded.   A   simple  security   mechanism  for
  309.  
  310.     encrypting/decrypting files  has been  added. More  significantly, this
  311.  
  312.     version introduces a very  powerful event handling mechanism  which can
  313.  
  314.     be placed at  the core of  a windowing system.  Since windowing systems
  315.  
  316.     rely   on  mouse   support,  mouse   support  has   also  been   added.
  317.  
  318.  
  319.  
  320.     Each  version of  PSK  starting  with  version  1.1 contains  a special
  321.  
  322.     function  called  "PSKVersion".   This  function  is   responsible  for
  323.  
  324.     reporting the version  number of this  library. The version  number can
  325.  
  326.     be determined as shown in the following example.
  327.  
  328.  
  329.  
  330.     #include <stdio.H>
  331.  
  332.     #include "psk.H"
  333.  
  334.  
  335.  
  336.     void main (void)
  337.  
  338.     {
  339.  
  340.        int version;
  341.  
  342.  
  343.  
  344.        version = PSKVersion ();
  345.  
  346.        printf ("PSK %d.%d\n", version/16, version%16);
  347.  
  348.     }
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.                                      - 3 -
  374.  
  375.  
  376.  
  377.  
  378.               -1Chapter 1 ■ Character Classification and Conversion-0
  379.  
  380.  
  381.  
  382.  
  383.  
  384.     Borland C++  contains a  variety of  macros in  CTYPE.H for classifying
  385.  
  386.     characters and converting  characters from one  case to another.  In my
  387.  
  388.     experience, I have  found these macros  to fail unexpectedly  at times.
  389.  
  390.     Therefore, I avoid using them  and work with my own  functions instead.
  391.  
  392.     CLASSCVT.H  contains  the  prototypes  for  these  functions.  In   the
  393.  
  394.     following, when I  refer to character,  I actually mean  the ASCII code
  395.  
  396.     of the character.
  397.  
  398.  
  399.  
  400.     -1Prototype-0: int isalnum (int c);
  401.  
  402.  
  403.  
  404.     Test the character passed in "c"  to see if it is alphanumeric.  Return
  405.  
  406.     nonzero    if    alphanumeric    (0-9,    A-Z,    a-z)    else    zero.
  407.  
  408.  
  409.  
  410.     -1Prototype-0: int isalpha (int c);
  411.  
  412.  
  413.  
  414.     Test the character  passed in "c"  to see if  it is alphabetic.  Return
  415.  
  416.     nonzero if alphabetic (A-Z, a-z) else zero.
  417.  
  418.  
  419.  
  420.     -1Prototype-0: int isdigit (int c);
  421.  
  422.  
  423.  
  424.     Test  the character  passed in  "c" to  see if  it is  a digit.  Return
  425.  
  426.     nonzero if digit (0-9) else zero.
  427.  
  428.  
  429.  
  430.     -1Prototype-0: int islower (int c);
  431.  
  432.  
  433.  
  434.     Test the  character passed  in "c"  to see  if it  is lowercase. Return
  435.  
  436.     nonzero if lowercase (a-z) else zero.
  437.  
  438.  
  439.  
  440.     -1Prototype-0: int isspace (int c);
  441.  
  442.  
  443.  
  444.     Test  the character  passed  in  "c"  to  see  if  it  is  a whitespace
  445.  
  446.     character. A whitespace character is  a character having an ASCII  code
  447.  
  448.     of 9, 10,  11, 12, 13,  or 32. These  codes correspond with  horizontal
  449.  
  450.     tabs,  line feeds,  vertical tabs,  form feeds,  carriage returns,  and
  451.  
  452.     spaces.  Return nonzero if whitespace else zero.
  453.  
  454.  
  455.  
  456.     -1Prototype-0: int isupper (int c);
  457.  
  458.  
  459.  
  460.     Test the  character passed  in "c"  to see  if it  is uppercase. Return
  461.  
  462.     nonzero if uppercase (A-Z) else zero.
  463.  
  464.  
  465.  
  466.     -1Prototype-0: int isxdigit (int c);
  467.  
  468.  
  469.  
  470.     Test the character passed  in "c" to see  if it is hexadecimal.  Return
  471.  
  472.     nonzero if hexadecimal (0-9, A-F, a-f) else zero.
  473.  
  474.  
  475.  
  476.     -1Prototype-0: int lower (int c);
  477.  
  478.  
  479.  
  480.     Convert  character  passed  in  "c"  to  lowercase.  Return   lowercase
  481.  
  482.     equivalent of uppercase character else character.
  483.  
  484.  
  485.  
  486.     -1Prototype-0: int upper (int c);
  487.  
  488.  
  489.  
  490.     Convert  character  passed  in  "c"  to  uppercase.  Return   uppercase
  491.  
  492.     equivalent of lowercase character else character.
  493.  
  494.  
  495.  
  496.  
  497.                                      - 4 -
  498.  
  499.  
  500.  
  501.  
  502.                       -1Chapter 2 ■ Critical Error Handler-0
  503.  
  504.  
  505.  
  506.  
  507.  
  508.     The Critical Error Handler  or CEH as it  is also called is  a software
  509.  
  510.     routine  that attempts  to  recover  from  a  variety  of  internal and
  511.  
  512.     external  errors that  would  prevent  a  program  from continuing.  It
  513.  
  514.     relys   on  user   input   to   decide   upon   a  course   of  action.
  515.  
  516.  
  517.  
  518.     Consider this example. A  program wants to open  a file and issues  the
  519.  
  520.     DOS services interrupt (21h) with  the "open file" function code  in AH
  521.  
  522.     (3dh). This file  is located on  a floppy disk  that has been  inserted
  523.  
  524.     into  drive A:  but  the  drive door  handle has  been left  open. What
  525.  
  526.     happens?
  527.  
  528.  
  529.  
  530.     Once interrupt  21h is  issued, the  DOS kernel  takes over. The kernel
  531.  
  532.     calls a device  driver. The driver  calles the BIOS  which communicates
  533.  
  534.     with  the  disk  controller  via  the  IN  and  OUT  machine   language
  535.  
  536.     instructions. Because  the controller  cannot read  the disk,  it sends
  537.  
  538.     error  information to  the  BIOS  which sends  this information  to the
  539.  
  540.     driver which  passes this  information on  to the  DOS kernel.  At this
  541.  
  542.     point,  the DOS  designers  could  have  done  one of  two things.  The
  543.  
  544.     kernel could  have always  sent the  error information  to the  program
  545.  
  546.     causing it  to deal  with the  error (the  FAIL option)  or the  kernel
  547.  
  548.     could have made  an attempt to  solve the problem  with user help  (the
  549.  
  550.     ABORT,  RETRY,  IGNORE,  and   sometimes  FAIL  prompt).  This   latter
  551.  
  552.     approach was chosen  and is more  flexible than the  previous approach.
  553.  
  554.     The user has the opportunity  of closing the door handle  and selecting
  555.  
  556.     RETRY.  This time, the operation should succeed.
  557.  
  558.  
  559.  
  560.     The ABORT option causes DOS to return to the COMMAND.COM drive  prompt.
  561.  
  562.     This option could prove fatal if a file has been opened by the  current
  563.  
  564.     program and  information has  been written  to that  file but  is still
  565.  
  566.     inside  a DOS  holding  buffer.  When  ABORT  is chosen,  this buffered
  567.  
  568.     information  is not  written to  disk and  the directory  entry is  not
  569.  
  570.     updated.
  571.  
  572.  
  573.  
  574.     RETRY allows  the DOS  kernel to  attempt the  operation again but this
  575.  
  576.     option is  generally only  useful if  the problem  is due  to leaving a
  577.  
  578.     drive  handle open  or  the  printer  being  offline.  In  these cases,
  579.  
  580.     closing the door handle  or placing the printer  online is all that  is
  581.  
  582.     needed to get the program running.
  583.  
  584.  
  585.  
  586.     The IGNORE  option is  a form  of gambling.  The DOS  kernel is told to
  587.  
  588.     ignore the  error and  let the  program continue.  If the  error is not
  589.  
  590.     too   serious  then   the  program   will  be   allowed  to   continue.
  591.  
  592.  
  593.  
  594.     DOS 3.30 introduced the FAIL  option. FAIL informs the kernel  that the
  595.  
  596.     program must be allowed to continue but an error code must be  returned
  597.  
  598.     for program examination.
  599.  
  600.  
  601.  
  602.     Upon  entry to  interrupt  24h  (the critical  error handler),  certain
  603.  
  604.     registers contain values  indicating the nature  of the error  and what
  605.  
  606.     course of action  needs to be  taken. Registers AH,  AL, BP:SI, and  DI
  607.  
  608.     contain this information.
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.                                      - 5 -
  622.  
  623.  
  624.  
  625.  
  626.     If bit 7 of AH is 0 then  the error was caused by a disk operation  and
  627.  
  628.     is known as a hard error. The  failing drive number is placed in AL  (0
  629.  
  630.     = A,  1 =  B, 2  = C,  etc). If  bit 5  is 1  then the IGNORE option is
  631.  
  632.     allowed. If bit 4 is  1 then the RETRY option  is allowed. If Bit 3  is
  633.  
  634.     1 then  the FAIL  option is  allowed. FAIL  is not  allowed on versions
  635.  
  636.     prior  to 3.30  and  IGNORE  may not  be allowed  on versions  3.30 and
  637.  
  638.     higher  because FAIL  is  present.  Bits 2  and 1  contain a  code that
  639.  
  640.     indicates  the affected  disk  area.  A  "00"  indicates  DOS,  a  "01"
  641.  
  642.     indicates  the file  allocation  table  (FAT),  a  "10"  indicates  the
  643.  
  644.     directory, and a "11" indicates the data  area. If bit 0 is 1 then  the
  645.  
  646.     operation that  was taking  place when  the error  occured was  a write
  647.  
  648.     otherwise it was a read.
  649.  
  650.  
  651.  
  652.     If bit 7  of AH is  1 then the  error was caused  by either a character
  653.  
  654.     device such  as the  printer or  a bad  memory image  of the FAT. BP:SI
  655.  
  656.     points to the device header of  the failing device. If the high  bit of
  657.  
  658.     the byte at  BP:[SI+4] is 1  then the error  is due to  a bad FAT image
  659.  
  660.     otherwise  it is  due  to  a character  device. AL  contains no  useful
  661.  
  662.     information if bit 7 of AH is 1.
  663.  
  664.  
  665.  
  666.     Regardless of what caused the  error (disk, device, or bad  FAT image),
  667.  
  668.     the  lower-half of  DI  contains  one  of  the  following  error codes.
  669.  
  670.  
  671.  
  672.     00h - write-protect violation
  673.  
  674.     01h - unknown drive number
  675.  
  676.     02h - drive not ready
  677.  
  678.     03h - unknown command (to controller)
  679.  
  680.     04h - CRC data error
  681.  
  682.     05h - bad request structure length
  683.  
  684.     06h - seek error
  685.  
  686.     07h - unknown media (disk) type
  687.  
  688.     08h - sector not found
  689.  
  690.     09h - printer out of paper
  691.  
  692.     0ah - error while writing
  693.  
  694.     0bh - error while reading
  695.  
  696.     0ch - general failure
  697.  
  698.  
  699.  
  700.     Upon exit, the  CEH returns a  code in AL  to let the  kernel know what
  701.  
  702.     action to take.
  703.  
  704.  
  705.  
  706.     0 - IGNORE
  707.  
  708.     1 - RETRY
  709.  
  710.     2 - ABORT
  711.  
  712.     3 - FAIL
  713.  
  714.  
  715.  
  716.     Since the CEH  is called by  the DOS kernel  and DOS is  not reentrant,
  717.  
  718.     only the following interrupt 21h  services can be used from  inside the
  719.  
  720.     handler. These services include 01h  to 0ch inclusive (the console  I/O
  721.  
  722.     services) and 59h (get  extended error information). Any  other service
  723.  
  724.     will cause the computer to lock up.
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.                                      - 6 -
  746.  
  747.  
  748.  
  749.  
  750.     The default critical error handler is actually located in the  resident
  751.  
  752.     portion  of the  COMMAND.COM  program.  There are  a few  problems with
  753.  
  754.     this handler.  First, if  ABORT is  chosen then  the current program is
  755.  
  756.     aborted as control returns  to the DOS prompt  (any data waiting to  be
  757.  
  758.     written to disk never arrives).  Second, the handler displays a  prompt
  759.  
  760.     on  screen  overwriting  the  current  contents.  The  critical   error
  761.  
  762.     handler  located in  the  CEH  module solves  both problems.  It allows
  763.  
  764.     only  two options:  RETRY and  ABORT. The  ABORT option  causes a  FAIL
  765.  
  766.     code to  be returned  to the  kernel. Therefore,  this handler can only
  767.  
  768.     be used with DOS versions 3.30 and higher.
  769.  
  770.  
  771.  
  772.     CEH.H contains the  function prototype for  the critical error  handler
  773.  
  774.     installation function.
  775.  
  776.  
  777.  
  778.     -1Prototype-0: void installceh (void);
  779.  
  780.  
  781.  
  782.     This function  installs the  critical error  handler. It  need only  be
  783.  
  784.     called  once  and   should  be  called   prior  to  any   disk  access.
  785.  
  786.  
  787.  
  788.     This  critical error  handler  consumes  a few  kilobytes of  memory. I
  789.  
  790.     have noticed  that it  may actually  confuse a  few users. Therefore, I
  791.  
  792.     decided to  create a  more streamlined  version of  the critical  error
  793.  
  794.     handler.  This handler  is  installed  via  the  "_installceh" function
  795.  
  796.     (whose prototype  is also  found in  CEH.H). The  streamlined CEH  does
  797.  
  798.     not  display any  information  on  the  screen  when invoked.  The only
  799.  
  800.     action taken is to return a FAIL  code to DOS. DOS will then cause  the
  801.  
  802.     "failing"  interrupt 21h  function  to  return  an  error  code  to the
  803.  
  804.     application.
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.  
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.  
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833.  
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868.  
  869.                                      - 7 -
  870.  
  871.  
  872.  
  873.  
  874.                             -1Chapter 3 ■ Data Entry-0
  875.  
  876.  
  877.  
  878.  
  879.  
  880.     Every database  program requires  a means  of data  entry. PSK provides
  881.  
  882.     such  a  means  through  the  EDIT  module.  Several  data  types   are
  883.  
  884.     supported.
  885.  
  886.  
  887.  
  888.     Data entry occurs through  an entity known as  the -1field-0. The field  is
  889.  
  890.     a  screen area  that  displays  initial and  user-entered/user-selected
  891.  
  892.     values. Each one of the _edit  functions found in EDIT draws the  field
  893.  
  894.     upon entry.  Each assumes  that the  cursor has  been positioned to the
  895.  
  896.     left-most column of the field  and the video display attribute  used in
  897.  
  898.     drawing the field has been  selected. Each function takes an  -1operation-0
  899.  
  900.     argument.  If set  to  EDIT_DISP,  the function  exits as  soon as  the
  901.  
  902.     field is drawn. The  NUL value (defined in  KBD.H) is returned. If  set
  903.  
  904.     to EDIT_FETCH,  the function  solicits input  after drawing  the field.
  905.  
  906.     EDIT_DISP is useful in displaying initial values for data entry  forms.
  907.  
  908.     EDIT.H contains the function prototypes.
  909.  
  910.  
  911.  
  912.     -1Prototype-0: int _editc (char *c, int width, int operation);
  913.  
  914.  
  915.  
  916.     Display and/or  request a  character string.  A character  string is  a
  917.  
  918.     string of ASCII  characters ending with  an ASCII NULL  (\0) character.
  919.  
  920.     All characters preceeding  the NULL character  are restricted to  those
  921.  
  922.     having ASCII codes in  the range 32 to  126 inclusive. The initial  and
  923.  
  924.     final  character strings  are pointed  to by  "c". The  field width  is
  925.  
  926.     passed in  "width". The  buffer pointed  to by  "c" must  be capable of
  927.  
  928.     holding width+1  characters (the  last character  is an  ASCII NULL). A
  929.  
  930.     variety of editting keys may be used including LEFT, RIGHT, HOME,  END,
  931.  
  932.     INS, BS,  and DEL.  RET, UP,  DOWN, and  ESC are  used to  and returned
  933.  
  934.     upon exit.  Changes are  discarded if  ESC is  returned otherwise  they
  935.  
  936.     are kept.
  937.  
  938.  
  939.  
  940.     -1Prototype-0: int _editd (char *d, int operation);
  941.  
  942.  
  943.  
  944.     Display and/or request a  date. A date is  a special kind of  character
  945.  
  946.     string consisting of  exactly eight ASCII  digits ending with  an ASCII
  947.  
  948.     NULL  character. The  digits  are  arranged in  YYYYMMDD order.  The MM
  949.  
  950.     and DD components start at 01 each and must fall within certain  limits
  951.  
  952.     (ex: 01  <= MM  <= 12).  YYYY can  range from  0000 to 9999. The buffer
  953.  
  954.     pointed to by "d" must be capable of holding nine characters (the  last
  955.  
  956.     character is an  ASCII NULL). The  initial value must  be a valid  date
  957.  
  958.     in  YYYYMMDD format.  The  final  value is  in this  format as  well. A
  959.  
  960.     variety  of editting  keys may  be used  including HOME,  END, and  BS.
  961.  
  962.     RET, UP,  DOWN, and  ESC are  used to  and returned  upon exit. Changes
  963.  
  964.     are discarded if ESC is  returned otherwise they are kept.  However, If
  965.  
  966.     the user attempts to exit by  pressing RET, UP, or DOWN and  an invalid
  967.  
  968.     date has been specified  then an error message  is flashed on the  last
  969.  
  970.     row of the screen.  The user must press  any key to erase  this message
  971.  
  972.     and then enter an appropriate date.
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979.  
  980.  
  981.  
  982.  
  983.  
  984.  
  985.  
  986.  
  987.  
  988.  
  989.  
  990.  
  991.  
  992.  
  993.                                      - 8 -
  994.  
  995.  
  996.  
  997.  
  998.     -1Prototype-0: int _editl (char **l, int *d, int operation);
  999.  
  1000.  
  1001.  
  1002.     Display and/or request a choice  string from a list of  choice strings.
  1003.  
  1004.     A  choice string  is associated  with an  index relative  to zero.  The
  1005.  
  1006.     address  of this  index  is  passed  in  "d".  Only  the choice  string
  1007.  
  1008.     indexed  by "d"  is  displayed.  The user  cycles through  the list  by
  1009.  
  1010.     pressing the spacebar  to move in  a forward direction  or ALT-spacebar
  1011.  
  1012.     to  move backwards  until an  appropriate choice  string is  displayed.
  1013.  
  1014.     This has the  effect of updating  the index. The  choice list array  is
  1015.  
  1016.     pointed to  by "l".  The last  entry must  be a  NULL address. RET, UP,
  1017.  
  1018.     DOWN, and ESC  are used to  and returned upon  exit. If ESC  is pressed
  1019.  
  1020.     then "d" is not updated.
  1021.  
  1022.  
  1023.  
  1024.     -1Prototype-0: int _editn (double *n, int width, int dd, int operation);
  1025.  
  1026.  
  1027.  
  1028.     Display and/or  request a  number. The  initial and  final numbers  are
  1029.  
  1030.     pointed to by  "n". The field  width is passed  in "width". The  number
  1031.  
  1032.     of digits after the  decimal point is passed  in "dd". The field  width
  1033.  
  1034.     must accomodate  the number  of decimal  digits and  the decimal point.
  1035.  
  1036.     A decimal point may be entered if  "dd" is not zero. It should only  be
  1037.  
  1038.     entered once. A  variety of editting  keys may be  used including LEFT,
  1039.  
  1040.     RIGHT, HOME, END,  INS, BS, and  DEL. RET, UP,  DOWN, and ESC  are used
  1041.  
  1042.     to and  returned upon  exit. Changes  are discarded  if ESC is returned
  1043.  
  1044.     otherwise they are kept.
  1045.  
  1046.  
  1047.  
  1048.     -1Prototype-0: int _editp (char *buf, char *pic, int operation);
  1049.  
  1050.  
  1051.  
  1052.     Display and/or request  a picture string.  A picture string  is divided
  1053.  
  1054.     into two parts: data buffer  and picture mask. Actual data  is obtained
  1055.  
  1056.     from and  placed into  the data  buffer. The  picture mask  defines the
  1057.  
  1058.     way in which the  data will appear and  what characters can be  entered
  1059.  
  1060.     at each position within the mask.  A date is a special kind  of picture
  1061.  
  1062.     string. The data  buffer can only  hold eight ASCII  digits in YYYYMMDD
  1063.  
  1064.     order but  the picture  mask causes  this data  to appear in MM/DD/YYYY
  1065.  
  1066.     format. Data cannot  be entered in  the "/" positions.  The data buffer
  1067.  
  1068.     is  pointed to  by  "buf"  and  the  picture  mask  by "pic".  The mask
  1069.  
  1070.     identifies positions for editable characters and the kind of  character
  1071.  
  1072.     that  can be  entered  at  each  position  (digit  or  alphabetic). The
  1073.  
  1074.     buffer must  be large  enough to  hold all  editable characters plus an
  1075.  
  1076.     ASCII NULL character. Any character  appearing in "pic" that is  not an
  1077.  
  1078.     "a" or "9" is displayed  literally in the field. No  editable character
  1079.  
  1080.     will appear in this  position. A variety of  editting keys may be  used
  1081.  
  1082.     including HOME, END,  and BS. RET,  UP, DOWN, and  ESC are used  to and
  1083.  
  1084.     returned  upon  exit.  Changes   are  discarded  if  ESC   is  returned
  1085.  
  1086.     otherwise they are kept.
  1087.  
  1088.  
  1089.  
  1090.     HOME moves the  cursor to the  first editting position  and END to  the
  1091.  
  1092.     last. BACKSPACE erases the  character in the nearest  editting position
  1093.  
  1094.     to the left of the cursor and repositions the cursor to that  position.
  1095.  
  1096.     DEL  erases the  character  under  the current  position and  moves all
  1097.  
  1098.     characters  to the  right  one  character  left.  INS  toggles  between
  1099.  
  1100.     insert and  overwrite modes.  A flashing  block cursor  is displayed if
  1101.  
  1102.     overwrite mode is in effect.
  1103.  
  1104.  
  1105.  
  1106.  
  1107.  
  1108.  
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117.                                      - 9 -
  1118.  
  1119.  
  1120.  
  1121.  
  1122.     Each one  of the  _edit functions  preserves the  cursor shape  but not
  1123.  
  1124.     position.
  1125.  
  1126.  
  1127.  
  1128.     -1Prototype-0: void format (char *buf, char *dat, char *pic);
  1129.  
  1130.  
  1131.  
  1132.     The "format"  function is  to "_editp"  what "sprintf"  is to "printf".
  1133.  
  1134.     Use "format" to  output a picture  to a buffer  instead of the  screen.
  1135.  
  1136.     The picture mask  is pointed to  by "pic". The  actual data is  pointed
  1137.  
  1138.     to by "dat".  The buffer is  pointed to by  "buf". "Buf" should  be the
  1139.  
  1140.     same size as "pic".
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.  
  1150.  
  1151.  
  1152.  
  1153.  
  1154.  
  1155.  
  1156.  
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212.  
  1213.  
  1214.  
  1215.  
  1216.  
  1217.  
  1218.  
  1219.  
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240.  
  1241.                                     - 10 -
  1242.  
  1243.  
  1244.  
  1245.  
  1246.                                -1Chapter 4 ■ Dates-0
  1247.  
  1248.  
  1249.  
  1250.  
  1251.  
  1252.     The DATE data  type is important  in database applications.  DBASE III+
  1253.  
  1254.     provides a  separate classification  for dates  in the  DBF file format
  1255.  
  1256.     (see Appendix B). PSK uses the  same format as DBASE when dealing  with
  1257.  
  1258.     dates.  This  format  is  an  eight-digit  ASCII  string  organized  as
  1259.  
  1260.     YYYYMMDD  where YYYY  represents four  year digits,  MM represents  two
  1261.  
  1262.     month digits,  and DD  represents two  day digits.  DATETIME.H contains
  1263.  
  1264.     the  function prototypes  for  those  functions that  work with  dates.
  1265.  
  1266.  
  1267.  
  1268.     -1Prototype-0: void datei (char *date);
  1269.  
  1270.  
  1271.  
  1272.     Increment  date by  one  day.  Account  for  leap  years.  For example,
  1273.  
  1274.     datei  will correctly  advance  19920228  to 19920229  and 19930228  to
  1275.  
  1276.     19930301.  A valid  date  in  the  form  YYYYMMDD  must  be passed  via
  1277.  
  1278.     "date".   This   will   be   replaced   by   the   incremented    date.
  1279.  
  1280.  
  1281.  
  1282.     -1Prototype-0: void datex (char *date, int *year, int *month, int *day);
  1283.  
  1284.  
  1285.  
  1286.     Extract year,  month, and  day components  from the  date. A valid date
  1287.  
  1288.     in the form YYYYMMDD must be  passed via "date". The year component  is
  1289.  
  1290.     returned  via   "year",  month   via  "month",   and  day   via  "day".
  1291.  
  1292.  
  1293.  
  1294.     -1Prototype-0: int doy (char *date);
  1295.  
  1296.  
  1297.  
  1298.     Calculate the day of  the year that the  date falls upon. A  valid date
  1299.  
  1300.     in the form "YYYYMMDD" must be  passed via "date". The day of  the year
  1301.  
  1302.     which   can   range   from   1   to   366   inclusive   is    returned.
  1303.  
  1304.  
  1305.  
  1306.     -1Prototype-0: int fday (int year, int month);
  1307.  
  1308.  
  1309.  
  1310.     Determine the weekday  that the first  day of a  month falls upon.  The
  1311.  
  1312.     "year" must  be greater  than or  equal to  1583 and  the "month"  must
  1313.  
  1314.     range  from 1  to  12.  Do not  use a  year beyond  2500 as  additional
  1315.  
  1316.     corrections would  probably be  required. An  integer from  0 through 7
  1317.  
  1318.     representing  a   weekday  from   Sunday  to   Saturday  is   returned.
  1319.  
  1320.  
  1321.  
  1322.     -1Prototype-0: int isleap (int year);
  1323.  
  1324.  
  1325.  
  1326.     Determine if "year"  is a leap  year. The year  should range from  1583
  1327.  
  1328.     to 2500. A nonzero  value is returned if  the year is a  leap year else
  1329.  
  1330.     zero is returned.
  1331.  
  1332.  
  1333.  
  1334.     -1Prototype-0: int ndays (int month);
  1335.  
  1336.  
  1337.  
  1338.     Determine the number of  days in a month.  The "month" must range  from
  1339.  
  1340.     1  to 12.  If  month  is 2  (February) then  only 28  is returned.  The
  1341.  
  1342.     "isleap" function will  be needed to  make an adjustment  if necessary.
  1343.  
  1344.     The number of days in the month is returned.
  1345.  
  1346.  
  1347.  
  1348.  
  1349.  
  1350.  
  1351.  
  1352.  
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360.  
  1361.  
  1362.  
  1363.  
  1364.  
  1365.                                     - 11 -
  1366.  
  1367.  
  1368.  
  1369.  
  1370.                             -1Chapter 5 ■ Dialog Box-0
  1371.  
  1372.  
  1373.  
  1374.  
  1375.  
  1376.     The dialog box is a close  cousin to the message box (see  Chapter 11).
  1377.  
  1378.     Although nowhere near  as sophisticated as  a graphical user  interface
  1379.  
  1380.     dialog  box, the  PSK  dialog  box  provides  an elegant  mechanism for
  1381.  
  1382.     displaying  messages  and  prompting   for  a  decision  via   buttons.
  1383.  
  1384.     DIALOG.H contains the function  prototype for the dialog  box function.
  1385.  
  1386.  
  1387.  
  1388.     A button is  a rectangle surrounding  a word which  indicates a choice.
  1389.  
  1390.     For  example,  YES  and  NO.  One  of  the  letters  in  each  word  is
  1391.  
  1392.     highlighted. The  highlighted letter  is known  as a  hotkey letter.  A
  1393.  
  1394.     button  is selected  in one  of two  ways. Pressing  the hotkey  letter
  1395.  
  1396.     selects  the button.  Pressing  this  letter a  second time  closes the
  1397.  
  1398.     dialog box and returns the  hotkey letter to the application.  The TAB,
  1399.  
  1400.     SHIFT TAB, LEFT ARROW, and RIGHT ARROW keys can also be used to  select
  1401.  
  1402.     a button.  The RETURN  key will  close the  dialog box  and return  the
  1403.  
  1404.     hotkey letter associated  with the current  button to the  application.
  1405.  
  1406.     The   current  button   is   surrounded   by   a   double-line  border.
  1407.  
  1408.  
  1409.  
  1410.     -1Prototype-0: int dialog (int col, int row, DIALOG *d);
  1411.  
  1412.  
  1413.  
  1414.     Display  a dialog  box  described  by  "d"  and await  user input.  The
  1415.  
  1416.     dialog box is displayed with  its upper-left corner specified by  "col"
  1417.  
  1418.     and "row".  If "col"  is given  a value  of -1  then the  dialog box is
  1419.  
  1420.     column-centered. If "row" is  given a value of  -1 then the dialog  box
  1421.  
  1422.     is row-centered. DIALOG.H contains  a typedef for the  DIALOG structure
  1423.  
  1424.     along  with a  CENTER constant  that can  be used  in centering  dialog
  1425.  
  1426.     boxes.
  1427.  
  1428.  
  1429.  
  1430.     typedef struct
  1431.  
  1432.     {
  1433.  
  1434.        int ntitles;
  1435.  
  1436.        char **titles;
  1437.  
  1438.        int tlattr;
  1439.  
  1440.        int nchoices;
  1441.  
  1442.        char **choices;
  1443.  
  1444.        int chattr;
  1445.  
  1446.        int *hotkeys;
  1447.  
  1448.        int hkattr;
  1449.  
  1450.        int bdattr;
  1451.  
  1452.     }
  1453.  
  1454.     DIALOG;
  1455.  
  1456.  
  1457.  
  1458.     The ntitles variable refers to the number of titles that are  displayed
  1459.  
  1460.     above  the button  menu.  The  titles variable  points to  an array  of
  1461.  
  1462.     pointers  to the  title  strings.  The  tlattr  variable  contains  the
  1463.  
  1464.     attribute used in displaying  each title. The nchoices  variable refers
  1465.  
  1466.     to  the number  of button  choices available  in the  button menu.  The
  1467.  
  1468.     choices variable points  to an array  of pointers to  the button choice
  1469.  
  1470.     names. The attribute used in  displaying all button names is  contained
  1471.  
  1472.     in the  chattr variable.  Each name  can contain  a specific  character
  1473.  
  1474.     called a  hotkey that,  when pressed,  selects a  button or  causes the
  1475.  
  1476.     dialog  box  to  close  and  that  character  to  be  returned  to  the
  1477.  
  1478.     application.  The hotkeys  variable  points  to  an  array  of  integer
  1479.  
  1480.     offsets  (relative to  zero)  that  identify  this  hotkey within  each
  1481.  
  1482.     button  name. The  hkattr  variable  contains  the  attribute  used  in
  1483.  
  1484.     displaying  each hotkey  character.  The  bdattr variable  contains the
  1485.  
  1486.     attribute  used in  displaying  all  borders  within  the  dialog  box.
  1487.  
  1488.  
  1489.                                     - 12 -
  1490.  
  1491.  
  1492.  
  1493.  
  1494.     This function returns  -1 if it  is unable to  allocate dynamic memory.
  1495.  
  1496.     Otherwise, it  returns the  hotkey character  (converted to  uppercase)
  1497.  
  1498.     associated with the current button.  The cursor shape and location  are
  1499.  
  1500.     preserved.
  1501.  
  1502.  
  1503.  
  1504.  
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514.  
  1515.  
  1516.  
  1517.  
  1518.  
  1519.  
  1520.  
  1521.  
  1522.  
  1523.  
  1524.  
  1525.  
  1526.  
  1527.  
  1528.  
  1529.  
  1530.  
  1531.  
  1532.  
  1533.  
  1534.  
  1535.  
  1536.  
  1537.  
  1538.  
  1539.  
  1540.  
  1541.  
  1542.  
  1543.  
  1544.  
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.  
  1569.  
  1570.  
  1571.  
  1572.  
  1573.  
  1574.  
  1575.  
  1576.  
  1577.  
  1578.  
  1579.  
  1580.  
  1581.  
  1582.  
  1583.  
  1584.  
  1585.  
  1586.  
  1587.  
  1588.  
  1589.  
  1590.  
  1591.  
  1592.  
  1593.  
  1594.  
  1595.  
  1596.  
  1597.  
  1598.  
  1599.  
  1600.  
  1601.  
  1602.  
  1603.  
  1604.  
  1605.  
  1606.  
  1607.  
  1608.  
  1609.  
  1610.  
  1611.  
  1612.  
  1613.                                     - 13 -
  1614.  
  1615.  
  1616.  
  1617.  
  1618.                           -1Chapter 6 ■ Event Handling-0
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.     Event  handling is  an  important  component  of  modern user-interface
  1625.  
  1626.     design.  An event  is  an  activity  that  occurs independently  of the
  1627.  
  1628.     execution of a  program. Examples include  mouse cursor movements,  key
  1629.  
  1630.     presses, mouse  button presses/releases,  and timer  time-outs. The job
  1631.  
  1632.     of the event handler  is to capture these  events and store them  in an
  1633.  
  1634.     event  queue where  they  remain  until processed.  A queue  is a  data
  1635.  
  1636.     structure where  information is  inserted at  one end  and removed from
  1637.  
  1638.     the  other. EVENT.H  contains  the  function prototypes  for the  event
  1639.  
  1640.     handling functions.
  1641.  
  1642.  
  1643.  
  1644.     -1Prototype-0: int e_close (void);
  1645.  
  1646.  
  1647.  
  1648.     The  "e_close" function  shuts down  the event  handler. This  function
  1649.  
  1650.     must be called before the program can exit otherwise the computer  will
  1651.  
  1652.     be  left in  an  unstable  state  and  will  undoubtedly  crash. OK  is
  1653.  
  1654.     returned  on success  or  ERROR  if  the  event  handler  has not  been
  1655.  
  1656.     installed.
  1657.  
  1658.  
  1659.  
  1660.     -1Prototype-0: int e_fetch (event *e);
  1661.  
  1662.  
  1663.  
  1664.     The "e_fetch"  function fetches  the next  event from  the event queue.
  1665.  
  1666.     It will not return until there  is an event waiting to be  fetched. The
  1667.  
  1668.     address  of an  event  structure  is  passed  to this  function. It  is
  1669.  
  1670.     composed of  five fields.  The "type"  field identifies  which kind  of
  1671.  
  1672.     event occurred:  KEY, MOUSE,  or TIMER.  If a  KEY event  occurred then
  1673.  
  1674.     "parm1" contains the ASCII or extended  ASCII code of the key that  was
  1675.  
  1676.     pressed. If  a MOUSE  event occurred  then the  subevent(s) responsible
  1677.  
  1678.     for generating  a MOUSE  event are  identified by  a list  of bit flags
  1679.  
  1680.     found in  "parm1". EVENT.H  defines constants  beginning with  ME_ that
  1681.  
  1682.     describe these subevents. The state  of the mouse buttons can  be found
  1683.  
  1684.     in "parm2". Bit  positions 0 and  1 contain the  settings for the  left
  1685.  
  1686.     and  right mouse  buttons  respectively.  If  a  three-button  Logitech
  1687.  
  1688.     mouse is being used then bit position 2 has the setting for the  middle
  1689.  
  1690.     button.  A zero  setting  indicates  that the  button is  not currently
  1691.  
  1692.     being pressed.  The cursor  column can  be found  in "parm3" and cursor
  1693.  
  1694.     row  in "parm4".  Both  values  are  pixel  values.  If  a TIMER  event
  1695.  
  1696.     occurred  then "parm1"  contains  a  value  that  identifies the  timer
  1697.  
  1698.     responsible for  generating the  event. OK  is returned  on success  or
  1699.  
  1700.     ERROR    if   the    event    handler    has   not    been   installed.
  1701.  
  1702.  
  1703.  
  1704.     -1Prototype-0: int e_flush (void);
  1705.  
  1706.  
  1707.  
  1708.     The "e_flush"  function removes  waiting events  from the  event queue.
  1709.  
  1710.     OK is returned on  success or ERROR if  the event handler has  not been
  1711.  
  1712.     installed.
  1713.  
  1714.  
  1715.  
  1716.     -1Prototype-0: int e_hide (void);
  1717.  
  1718.  
  1719.  
  1720.     The  "e_hide" function  makes the  mouse cursor  invisible (unless  the
  1721.  
  1722.     "e_show" function has  been called two  or more times  prior to calling
  1723.  
  1724.     "e_hide"). This depends  on there being  an installed mouse  driver. OK
  1725.  
  1726.     is returned  on success  or ERROR  if the  event handler  has not  been
  1727.  
  1728.     installed.
  1729.  
  1730.  
  1731.  
  1732.  
  1733.  
  1734.  
  1735.  
  1736.  
  1737.                                     - 14 -
  1738.  
  1739.  
  1740.  
  1741.  
  1742.  
  1743.  
  1744.     -1Prototype-0: int e_hook (int (*hook) (int ax, int bx, int cx, int dx),
  1745.  
  1746.                            void (*__mshow) (void), void (*__mhide)
  1747.  
  1748.                            (void));
  1749.  
  1750.  
  1751.  
  1752.     The "e_hook"  function hooks  three functions  into the  event handler.
  1753.  
  1754.     The  "_hook" function  is  called  whenever a  mouse event  occurs. The
  1755.  
  1756.     "__mshow" function is called whenever "e_show" is called and  "__mhide"
  1757.  
  1758.     whenever  "e_hide" is  called.  The  purpose of  these functions  is to
  1759.  
  1760.     extend the handler in graphics  mode to support mouse cursors  that are
  1761.  
  1762.     not supported by  the mouse driver.  For example, the  Hercules and EGA
  1763.  
  1764.     adaptors are not supported by  the Microsoft mouse driver. The  "_hook"
  1765.  
  1766.     function  is passed  four  parameters.  AX  contains  a list  of events
  1767.  
  1768.     defined  by bit  flags.  BX  contains  the  button  status.  CX and  DX
  1769.  
  1770.     contain the column  and row coordinates  respectively. A nonzero  value
  1771.  
  1772.     is returned  from "_hook"  to abort  the mouse  event. A  zero value is
  1773.  
  1774.     returned otherwise.
  1775.  
  1776.  
  1777.  
  1778.     -1Prototype-0: int e_init (int maxevents);
  1779.  
  1780.  
  1781.  
  1782.     The "e_init" function  installs the event  handler. The maximum  number
  1783.  
  1784.     of  events that  can  be  stored  in  the  event  queue  is  passed  in
  1785.  
  1786.     "maxevents". If  the event  queue is  full then  additional events  are
  1787.  
  1788.     ignored. If  the event  handler is  successfully installed  then OK  is
  1789.  
  1790.     returned otherwise ERROR.
  1791.  
  1792.  
  1793.  
  1794.     -1Prototype-0: int e_mstatus (int *exist, int *nbuttons);
  1795.  
  1796.  
  1797.  
  1798.     The "e_mstatus"  function returns  the mouse  status. If  the mouse  is
  1799.  
  1800.     present then  "*exist" will  be set  to a  nonzero value otherwise zero
  1801.  
  1802.     will be  used. The  number of  buttons is  passed back  to "*nbuttons".
  1803.  
  1804.     OK is returned on  success or ERROR if  the event handler has  not been
  1805.  
  1806.     installed.
  1807.  
  1808.  
  1809.  
  1810.     -1Prototype-0:int e_resume (void);
  1811.  
  1812.  
  1813.  
  1814.     The "e_resume" function resumes  event handling after a  suspension. OK
  1815.  
  1816.     is returned  on success  or ERROR  if the  event handler  has not  been
  1817.  
  1818.     installed.
  1819.  
  1820.  
  1821.  
  1822.     -1Prototype-0: int e_settimer (int id, int value);
  1823.  
  1824.  
  1825.  
  1826.     The  "e_settimer" function  initializes  and  activates a  timer. There
  1827.  
  1828.     are  a total  of NTIMER  timers that  may be  used. Each  timer has  an
  1829.  
  1830.     identifier which  is passed  in "id".  The identifier  can range from 0
  1831.  
  1832.     to  NTIMER-1. An  initial  value  is passed  in "value"  and the  timer
  1833.  
  1834.     begins  counting down  from  this  value.  Once  the timer  has reached
  1835.  
  1836.     zero, a timer  event occurs and  the timer is  reset to this  value. OK
  1837.  
  1838.     is  returned  on  success  or  ERROR  if  the  event  handler  has  not
  1839.  
  1840.     been   installed  or   the   timer   identifier   is   out  of   range.
  1841.  
  1842.  
  1843.  
  1844.     -1Prototype-0: int e_show (void);
  1845.  
  1846.  
  1847.  
  1848.     The "e_show" function makes  the mouse cursor visible  (unless "e_hide"
  1849.  
  1850.     has been  called two  or more  times prior  to calling  "e_show"). This
  1851.  
  1852.     depends on there being an  installed mouse driver. The mouse  cursor is
  1853.  
  1854.     invisible by default. OK is returned  on success or ERROR if the  event
  1855.  
  1856.     handler has not been installed.
  1857.  
  1858.  
  1859.  
  1860.  
  1861.                                     - 15 -
  1862.  
  1863.  
  1864.  
  1865.  
  1866.  
  1867.  
  1868.     -1Prototype-0: int e_srstatus (int *sflag);
  1869.  
  1870.  
  1871.  
  1872.     The "e_srstatus" function returns  the event handler status  by passing
  1873.  
  1874.     the  current status  back  to  "*sflag" (suspension  is indicated  by a
  1875.  
  1876.     nonzero  value). OK  is  returned  on  success  or ERROR  if the  event
  1877.  
  1878.     handler has not been installed.
  1879.  
  1880.  
  1881.  
  1882.     -1Prototype-0: int e_stoptimer (int id);
  1883.  
  1884.  
  1885.  
  1886.     The  "e_stoptimer" function  stops the  timer identified  by the  value
  1887.  
  1888.     passed in "id" which must range  from 0 to NTIMER-1. OK is  returned on
  1889.  
  1890.     success or ERROR  if the event  handler has not  been installed or  the
  1891.  
  1892.     timer identifier is out of range.
  1893.  
  1894.  
  1895.  
  1896.     -1Prototype-0: int e_suspend (void);
  1897.  
  1898.  
  1899.  
  1900.     The  "e_suspend" function  suspends  the  event handler.  TIMER, MOUSE,
  1901.  
  1902.     and  KEY events  are  ignored  until  the  handler is  reactivated with
  1903.  
  1904.     "e_resume".
  1905.  
  1906.  
  1907.  
  1908.     -1Prototype-0: int e_tstatus (int id, int *eflag, int *value);
  1909.  
  1910.  
  1911.  
  1912.     The "e_tstatus" function returns the status of the timer identified  by
  1913.  
  1914.     the  value passed  in  id  which  must  range from  0 to  NTIMER-1. The
  1915.  
  1916.     enabled  status is  passed back  to "*eflag"  (a nonzero  value if  the
  1917.  
  1918.     timer  is active  otherwise  zero).  The  initial  value  starting  the
  1919.  
  1920.     countdown is  passed to  "*value". OK  is returned  on success or ERROR
  1921.  
  1922.     if the event handler has not been installed or the timer identifier  is
  1923.  
  1924.     out of range.
  1925.  
  1926.  
  1927.  
  1928.  
  1929.  
  1930.  
  1931.  
  1932.  
  1933.  
  1934.  
  1935.  
  1936.  
  1937.  
  1938.  
  1939.  
  1940.  
  1941.  
  1942.  
  1943.  
  1944.  
  1945.  
  1946.  
  1947.  
  1948.  
  1949.  
  1950.  
  1951.  
  1952.  
  1953.  
  1954.  
  1955.  
  1956.  
  1957.  
  1958.  
  1959.  
  1960.  
  1961.  
  1962.  
  1963.  
  1964.  
  1965.  
  1966.  
  1967.  
  1968.  
  1969.  
  1970.  
  1971.  
  1972.  
  1973.  
  1974.  
  1975.  
  1976.  
  1977.  
  1978.  
  1979.  
  1980.  
  1981.  
  1982.  
  1983.  
  1984.  
  1985.                                     - 16 -
  1986.  
  1987.  
  1988.  
  1989.  
  1990.                         -1Chapter 7 ■ File and Directory-0
  1991.  
  1992.  
  1993.  
  1994.  
  1995.  
  1996.     Certain applications need to know if a file exists prior to  performing
  1997.  
  1998.     some  operation. Other  applications  may  need to  generate a  menu of
  1999.  
  2000.     file names  in a  format similar  to the  DIR command.  The ability  to
  2001.  
  2002.     rename  directories  may  also   prove  to  be  handy.   The  following
  2003.  
  2004.     functions  perform these  tasks  on  behalf  of  the application.  FD.H
  2005.  
  2006.     contains the function prototypes.
  2007.  
  2008.  
  2009.  
  2010.     -1Prototype-0: void fde (struct ffblk *de, char *buffer);
  2011.  
  2012.  
  2013.  
  2014.     Format a directory entry. The  address of an entry block  obtained from
  2015.  
  2016.     "findfirst/findnext" is passed in "de" and the address of a buffer  for
  2017.  
  2018.     holding the result is passed in  "buffer". The size of the buffer  must
  2019.  
  2020.     be  exactly DESIZE  bytes. The  result is  an ASCIZ  string similar  to
  2021.  
  2022.     that produced by the DIR command.
  2023.  
  2024.  
  2025.  
  2026.     -1Prototype-0: int fdexist (char *filespec);
  2027.  
  2028.  
  2029.  
  2030.     Determine  if  a  file  or   directory  exists.  The  address  of   the
  2031.  
  2032.     file/directory specification is passed  in "filespec". A nonzero  value
  2033.  
  2034.     is returned if the file exists.
  2035.  
  2036.  
  2037.  
  2038.     -1Prototype-0: int nmdir (char *oname, char *nname);
  2039.  
  2040.  
  2041.  
  2042.     Rename a  directory. The  old name  is passed  in "oname"  and the  new
  2043.  
  2044.     name in "nname".  If successful, the  directory is renamed  and zero is
  2045.  
  2046.     returned. A  -1 is  returned if  the directory  cannot be renamed. This
  2047.  
  2048.     will  be the  case  if  a directory  with the  same name  exists or  an
  2049.  
  2050.     attempt  is  made  to  rename  a  directory  located  in  a   different
  2051.  
  2052.     directory.
  2053.  
  2054.  
  2055.  
  2056.     The  following example  illustrates how  "fde" and  "fdexist" might  be
  2057.  
  2058.     used.  This example  displays  a  list  of  files in  a directory  in a
  2059.  
  2060.     DIR-similar format.
  2061.  
  2062.  
  2063.  
  2064.     #include <dir.H>
  2065.  
  2066.     #include <dos.H>
  2067.  
  2068.     #include <process.H>
  2069.  
  2070.     #include <stdio.H>
  2071.  
  2072.  
  2073.  
  2074.     #include "fd.H"
  2075.  
  2076.  
  2077.  
  2078.     void main (int argc, char **argv)
  2079.  
  2080.     {
  2081.  
  2082.        int done;
  2083.  
  2084.        struct ffblk ffblk;
  2085.  
  2086.        char buffer [DESIZE];
  2087.  
  2088.  
  2089.  
  2090.        if (argc != 2)
  2091.  
  2092.        {
  2093.  
  2094.            printf ("invalid command line\n");
  2095.  
  2096.            exit (1);
  2097.  
  2098.        }
  2099.  
  2100.  
  2101.  
  2102.        if (!fdexist (argv [1]))
  2103.  
  2104.            exit (1);
  2105.  
  2106.  
  2107.  
  2108.  
  2109.                                     - 17 -
  2110.  
  2111.  
  2112.  
  2113.  
  2114.        printf ("Directory listing of %s\n", argv [1]);
  2115.  
  2116.        done = findfirst (argv [1], &ffblk, FA_NORMAL);
  2117.  
  2118.        while (!done)
  2119.  
  2120.        {
  2121.  
  2122.           fde (&ffblk, buffer);
  2123.  
  2124.           puts (buffer);
  2125.  
  2126.           done = findnext (&ffblk);
  2127.  
  2128.        }
  2129.  
  2130.  
  2131.  
  2132.        exit (0);
  2133.  
  2134.     }
  2135.  
  2136.  
  2137.  
  2138.  
  2139.  
  2140.  
  2141.  
  2142.  
  2143.  
  2144.  
  2145.  
  2146.  
  2147.  
  2148.  
  2149.  
  2150.  
  2151.  
  2152.  
  2153.  
  2154.  
  2155.  
  2156.  
  2157.  
  2158.  
  2159.  
  2160.  
  2161.  
  2162.  
  2163.  
  2164.  
  2165.  
  2166.  
  2167.  
  2168.  
  2169.  
  2170.  
  2171.  
  2172.  
  2173.  
  2174.  
  2175.  
  2176.  
  2177.  
  2178.  
  2179.  
  2180.  
  2181.  
  2182.  
  2183.  
  2184.  
  2185.  
  2186.  
  2187.  
  2188.  
  2189.  
  2190.  
  2191.  
  2192.  
  2193.  
  2194.  
  2195.  
  2196.  
  2197.  
  2198.  
  2199.  
  2200.  
  2201.  
  2202.  
  2203.  
  2204.  
  2205.  
  2206.  
  2207.  
  2208.  
  2209.  
  2210.  
  2211.  
  2212.  
  2213.  
  2214.  
  2215.  
  2216.  
  2217.  
  2218.  
  2219.  
  2220.  
  2221.  
  2222.  
  2223.  
  2224.  
  2225.  
  2226.  
  2227.  
  2228.  
  2229.  
  2230.  
  2231.  
  2232.  
  2233.                                     - 18 -
  2234.  
  2235.  
  2236.  
  2237.  
  2238.                            -1Chapter 8 ■ Game Support-0
  2239.  
  2240.  
  2241.  
  2242.  
  2243.  
  2244.     PSK was not originally  designed to support game  development. However,
  2245.  
  2246.     things have changed.  PSK now offers  support for background  music and
  2247.  
  2248.     joysticks. GAME.H  contains function  prototypes and  useful constants.
  2249.  
  2250.  
  2251.  
  2252.     -1Prototype-0: void bmusic (int cmd, ...);
  2253.  
  2254.  
  2255.  
  2256.     The  "bmusic" function  offers  background  music  capability  to  your
  2257.  
  2258.     application. This  is accomplished  by redirecting  interrupt 1ch.  The
  2259.  
  2260.     format of the  arguments list depends  upon the value  passed in "cmd".
  2261.  
  2262.     If BM_OPEN  or BM_CLOSE  are passed  then no  additional arguments  are
  2263.  
  2264.     specified. If BM_PLAY is  passed then a char  * argument pointing to  a
  2265.  
  2266.     song buffer  must be  specified immediately  after "cmd".  BM_OPEN must
  2267.  
  2268.     be passed before  passing BM_PLAY. BM_CLOSE  must be passed  before the
  2269.  
  2270.     application  exits. Play  does  not  begin  until  BM_PLAY  is  passed.
  2271.  
  2272.  
  2273.  
  2274.     The characters specified  in the song  buffer must be  in ASCII format.
  2275.  
  2276.     These characters define a language similar to the BASIC PLAY  language.
  2277.  
  2278.     In addition to the notes A, A#, B,  C, C#, D, D#, E, F, F#, G,  and G#,
  2279.  
  2280.     the following commands are defined.
  2281.  
  2282.  
  2283.  
  2284.     ■ O (set octave)
  2285.  
  2286.  
  2287.  
  2288.     Syntax: O#
  2289.  
  2290.  
  2291.  
  2292.     Set the current octave  to the octave specified  by # (# can  take on a
  2293.  
  2294.     value  from 1  to  5  inclusive).  The  default octave  is 2  (octave 3
  2295.  
  2296.     contains middle C).
  2297.  
  2298.  
  2299.  
  2300.     ■ L (set note length)
  2301.  
  2302.  
  2303.  
  2304.     Syntax: L#
  2305.  
  2306.  
  2307.  
  2308.     Set the  length of  all succeeding  notes to  that defined  by # (# can
  2309.  
  2310.     take on a value of 1 for  whole notes, 2 for half notes, 4  for quarter
  2311.  
  2312.     notes,  8 for  eighth notes,  or 6  for sixteenth  notes). The  default
  2313.  
  2314.     length is 4 (quarter notes).
  2315.  
  2316.  
  2317.  
  2318.     ■ R (reset)
  2319.  
  2320.  
  2321.  
  2322.     Syntax: R
  2323.  
  2324.  
  2325.  
  2326.     Generate a rest equal to the  length of a note using the  most recently
  2327.  
  2328.     specified note length.
  2329.  
  2330.  
  2331.  
  2332.     ■ X (cycle)
  2333.  
  2334.  
  2335.  
  2336.     Syntax: X
  2337.  
  2338.  
  2339.  
  2340.     Reset music to start of the song buffer.
  2341.  
  2342.  
  2343.  
  2344.  
  2345.  
  2346.  
  2347.  
  2348.  
  2349.  
  2350.  
  2351.  
  2352.  
  2353.  
  2354.  
  2355.  
  2356.  
  2357.                                     - 19 -
  2358.  
  2359.  
  2360.  
  2361.  
  2362.     ■ S (switch frequency table)
  2363.  
  2364.  
  2365.  
  2366.     Syntax: S
  2367.  
  2368.  
  2369.  
  2370.     An inverse frequency table has  been defined for special effects.  This
  2371.  
  2372.     command  toggles  back  and  forth  between  the  inverse  and   normal
  2373.  
  2374.     frequency tables.
  2375.  
  2376.  
  2377.  
  2378.     ■ 0 (select normal frequency table)
  2379.  
  2380.  
  2381.  
  2382.     Syntax: 0
  2383.  
  2384.  
  2385.  
  2386.     Select the normal frequency table (the default).
  2387.  
  2388.  
  2389.  
  2390.     ■ 1 (select inverse frequency table)
  2391.  
  2392.  
  2393.  
  2394.     Syntax: 1
  2395.  
  2396.  
  2397.  
  2398.     Select the inverse frequency table.
  2399.  
  2400.  
  2401.  
  2402.     -1Prototype-0: int button (void);
  2403.  
  2404.  
  2405.  
  2406.     Return the  status of  the joystick  buttons. The  status of  upto four
  2407.  
  2408.     buttons  is returned  simultaneously.  A  PC  can  accomodate upto  two
  2409.  
  2410.     joysticks and each joystick has  upto two buttons. The constants  J1B1,
  2411.  
  2412.     J1B2, J2B1, and  J2B2 defined in  GAME.H are used  in determining which
  2413.  
  2414.     button is pressed or not pressed.  For example:
  2415.  
  2416.  
  2417.  
  2418.     printf ("%d\n", button () & J1B1);
  2419.  
  2420.  
  2421.  
  2422.     will  display a  nonzero  value  if Joystick  1 Button  1 is  currently
  2423.  
  2424.     pressed. If  not pressed  then zero  would be  displayed. This function
  2425.  
  2426.     can  be  used   with  any  PC   computer  equipped  with   a  joystick.
  2427.  
  2428.  
  2429.  
  2430.     -1Prototype-0: int joystick (int code);
  2431.  
  2432.  
  2433.  
  2434.     Return  the current  joystick  position.  The result  depends upon  the
  2435.  
  2436.     value passed in "code". A zero  causes the X position of joystick  1 to
  2437.  
  2438.     be  returned. A  one  causes  the  Y  position  of  joystick  1  to  be
  2439.  
  2440.     returned. A two  causes the X  position of joystick  2 to be  returned.
  2441.  
  2442.     A  three causes  the  Y  position of  joystick 2  to be  returned. This
  2443.  
  2444.     function  can be  used  with  AT  computers  and  higher.  It does  not
  2445.  
  2446.     support PC or XT class  machines. I am experimenting with  a compatible
  2447.  
  2448.     technique for these machines and hope to have it available in the  next
  2449.  
  2450.     version of PSK.  This function will  always return zero  no matter what
  2451.  
  2452.     value is  passed in  "code" for  PC or  XT class  computers. Any  value
  2453.  
  2454.     passed  in "code"  which  is  not in  the range  0-3 is  treated as  3.
  2455.  
  2456.  
  2457.  
  2458.  
  2459.  
  2460.  
  2461.  
  2462.  
  2463.  
  2464.  
  2465.  
  2466.  
  2467.  
  2468.  
  2469.  
  2470.  
  2471.  
  2472.  
  2473.  
  2474.  
  2475.  
  2476.  
  2477.  
  2478.  
  2479.  
  2480.  
  2481.                                     - 20 -
  2482.  
  2483.  
  2484.  
  2485.  
  2486.                 -1Chapter 9 ■ Keyboard and Context-Sensitive Help-0
  2487.  
  2488.  
  2489.  
  2490.  
  2491.  
  2492.     PSK contains  a keyboard  handler with  an integrated context-sensitive
  2493.  
  2494.     help system and  a keystroke translation  facility. The handler  allows
  2495.  
  2496.     you to fetch keystrokes from  and check for the presence  of keystrokes
  2497.  
  2498.     in  the  BIOS  buffer.  The  help  system  allows  you  to  install   a
  2499.  
  2500.     context-handler function  which is  activated whenever  the F1 function
  2501.  
  2502.     key is pressed. A different context  can be specified at each point  in
  2503.  
  2504.     the program where keyboard input is required allowing a different  help
  2505.  
  2506.     screen  to be  displayed  when  F1  is  pressed. You  can instruct  the
  2507.  
  2508.     translation  facility  to  substitute  certain  keystrokes  with  other
  2509.  
  2510.     keystrokes. For example,  suppose you are  designing a data  entry form
  2511.  
  2512.     and want to use  the TAB key to  switch the input focus  from one field
  2513.  
  2514.     to another.  Unfortunately, the  data entry  functions (see  Chapter 3)
  2515.  
  2516.     do not  respond to  TAB but  they do  respond to  RET. You  can setup a
  2517.  
  2518.     translation  so  that  RET   is  returned  whenever  TAB   is  pressed.
  2519.  
  2520.  
  2521.  
  2522.     KBD.H  contains function  prototypes,  a  variety  of  useful keystroke
  2523.  
  2524.     constants,  and some  context-sensitve  help  constants.  These  latter
  2525.  
  2526.     constants  all begin  with  "CTX_"  You will  notice that  two contexts
  2527.  
  2528.     have  been defined:  CTX_CEH  and  CTX_MSG. CTX_CEH  is enabled  by the
  2529.  
  2530.     critical error handler upon  activation. If a context-handler  function
  2531.  
  2532.     has been established  then CTX_CEH will  be passed to  this function to
  2533.  
  2534.     identify that F1 has been  pressed while the critical error  handler is
  2535.  
  2536.     active.  Similarly, if  a  message  box is  displayed, CTX_MSG  will be
  2537.  
  2538.     passed  to this  function. When  defining your  own context  constants,
  2539.  
  2540.     define them  in terms  of CTX_USR.  I may  decide to  add several  more
  2541.  
  2542.     predefined context constants in future  versions of PSK. If you  define
  2543.  
  2544.     your constants  in terms  of CTX_USR  then you  will not  need to  make
  2545.  
  2546.     source  code changes  when  working  with  future  versions although  a
  2547.  
  2548.     recompile  will be  necessary.  The  example  program  illustrates  how
  2549.  
  2550.     context-sensitive help is used.
  2551.  
  2552.  
  2553.  
  2554.     -1Prototype-0: int k_fetch (void);
  2555.  
  2556.  
  2557.  
  2558.     Fetch keystroke. When a  key is pressed, the  actual value is saved  in
  2559.  
  2560.     an internal variable to be  retrieved by another function. The  key may
  2561.  
  2562.     then be  translated into  another key  (even F1  can be translated). If
  2563.  
  2564.     the result of the translation is F1 and a context-handler function  has
  2565.  
  2566.     been  installed and  this  function  is not  currently active  then the
  2567.  
  2568.     context-handler function will be  called using the most  recent context
  2569.  
  2570.     code.  Once you  return  from  the context-handler  function, you  will
  2571.  
  2572.     need  to press  another  key.  Either  the  actual  keystroke  that was
  2573.  
  2574.     pressed or a translated keystroke is returned.
  2575.  
  2576.  
  2577.  
  2578.     -1Prototype-0: void k_flush (void);
  2579.  
  2580.  
  2581.  
  2582.     Flush all  waiting keystrokes  from the  BIOS queue.  This may have the
  2583.  
  2584.     effect  of invoking  the  context-handler  function.  To  prevent this,
  2585.  
  2586.     pass a  NULL address  to the  "k_setctxfunc" function  prior to calling
  2587.  
  2588.     "k_flush" and restore the address afterward.
  2589.  
  2590.  
  2591.  
  2592.     -1Prototype-0: int k_getctx (void);
  2593.  
  2594.  
  2595.  
  2596.     Return the  current context  code. A  context code  is a  signed 16-bit
  2597.  
  2598.     integer.
  2599.  
  2600.  
  2601.  
  2602.  
  2603.  
  2604.  
  2605.                                     - 21 -
  2606.  
  2607.  
  2608.  
  2609.  
  2610.     -1Prototype-0: int k_iskey (void);
  2611.  
  2612.  
  2613.  
  2614.     Determine if a key has been  pressed. A nonzero value is returned  if a
  2615.  
  2616.     key was pressed else zero is returned.
  2617.  
  2618.  
  2619.  
  2620.     -1Prototype-0: int k_lastkey (void);
  2621.  
  2622.  
  2623.  
  2624.     Return the  code of  the last  untranslated keystroke  that was pressed
  2625.  
  2626.     (the default is zero). In  the previous example, if TAB  was translated
  2627.  
  2628.     to RET and TAB was pressed, "k_fetch" would return RET but  "k_lastkey"
  2629.  
  2630.     would return TAB.
  2631.  
  2632.  
  2633.  
  2634.     -1Prototype-0: void k_setctx (int ctx);
  2635.  
  2636.  
  2637.  
  2638.     Set the current context code to "ctx".
  2639.  
  2640.  
  2641.  
  2642.     -1Prototype-0: void k_setctxfunc (void (*ctxfunc) (int ctx));
  2643.  
  2644.  
  2645.  
  2646.     Set  the current  context-handler  function  to "ctxfunc".  If NULL  is
  2647.  
  2648.     passed then context-sensitive  help is disabled.  The default is  NULL.
  2649.  
  2650.  
  2651.  
  2652.     -1Prototype-0: int k_xtcount (void);
  2653.  
  2654.  
  2655.  
  2656.     Return the number of defined  translations. The maximum number is  128.
  2657.  
  2658.  
  2659.  
  2660.     -1Prototype-0: int k_xtdel (int okey);
  2661.  
  2662.  
  2663.  
  2664.     Remove the translation defined  for the keystroke specified  by "okey".
  2665.  
  2666.     If  the translation  was  removed  then zero  is returned.  If the  key
  2667.  
  2668.     specified  by  "okey"  could  not   be  found  then  -1  is   returned.
  2669.  
  2670.  
  2671.  
  2672.     -1Prototype-0: int k_xtins (int okey, int nkey);
  2673.  
  2674.  
  2675.  
  2676.     Establish a translation.  The original key  is specified by  "okey" and
  2677.  
  2678.     the new key  by "nkey". In  the previous example,  "okey" would be  set
  2679.  
  2680.     to TAB  and "nkey"  to RET.  If a  translation already  exists based on
  2681.  
  2682.     "okey" then the  translation is updated  to reflect the  new "nkey". If
  2683.  
  2684.     the translation  was installed  then zero  is returned.  If the maximum
  2685.  
  2686.     number  of  translations  has   been  reached  then  -1   is  returned.
  2687.  
  2688.  
  2689.  
  2690.     Prototype: int k_xtsize (void);
  2691.  
  2692.  
  2693.  
  2694.     Return the maximum size of  the translation table. The current  size is
  2695.  
  2696.     128.
  2697.  
  2698.  
  2699.  
  2700.  
  2701.  
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710.  
  2711.  
  2712.  
  2713.  
  2714.  
  2715.  
  2716.  
  2717.  
  2718.  
  2719.  
  2720.  
  2721.  
  2722.  
  2723.  
  2724.  
  2725.  
  2726.  
  2727.  
  2728.  
  2729.                                     - 22 -
  2730.  
  2731.  
  2732.  
  2733.  
  2734.                               -1Chapter 10 ■ Macros-0
  2735.  
  2736.  
  2737.  
  2738.  
  2739.  
  2740.     MACROS.H  contains references  to  two  constants,  one  macro, and  an
  2741.  
  2742.     include file. The ERROR and OK  constants can be used by your  programs
  2743.  
  2744.     to establish  uniformity. OK  is synonymous  with zero  making it  more
  2745.  
  2746.     efficient  to use  "if (!value)"  instead of  "if (value  == OK)".  The
  2747.  
  2748.     CENTER macro has been designed to make it easier to center windows  and
  2749.  
  2750.     text on the screen.  For example, CENTER(80, strlen  ("TITLE")) returns
  2751.  
  2752.     the centered  starting column  for TITLE.  A reference  to STDLIB.H  is
  2753.  
  2754.     made in  MACROS.H to  allow the  min/max macros  to be imported. Future
  2755.  
  2756.     versions   of   PSK   will   add   more   macros   to   this    header.
  2757.  
  2758.  
  2759.  
  2760.  
  2761.  
  2762.  
  2763.  
  2764.  
  2765.  
  2766.  
  2767.  
  2768.  
  2769.  
  2770.  
  2771.  
  2772.  
  2773.  
  2774.  
  2775.  
  2776.  
  2777.  
  2778.  
  2779.  
  2780.  
  2781.  
  2782.  
  2783.  
  2784.  
  2785.  
  2786.  
  2787.  
  2788.  
  2789.  
  2790.  
  2791.  
  2792.  
  2793.  
  2794.  
  2795.  
  2796.  
  2797.  
  2798.  
  2799.  
  2800.  
  2801.  
  2802.  
  2803.  
  2804.  
  2805.  
  2806.  
  2807.  
  2808.  
  2809.  
  2810.  
  2811.  
  2812.  
  2813.  
  2814.  
  2815.  
  2816.  
  2817.  
  2818.  
  2819.  
  2820.  
  2821.  
  2822.  
  2823.  
  2824.  
  2825.  
  2826.  
  2827.  
  2828.  
  2829.  
  2830.  
  2831.  
  2832.  
  2833.  
  2834.  
  2835.  
  2836.  
  2837.  
  2838.  
  2839.  
  2840.  
  2841.  
  2842.  
  2843.  
  2844.  
  2845.  
  2846.  
  2847.  
  2848.  
  2849.  
  2850.  
  2851.  
  2852.  
  2853.                                     - 23 -
  2854.  
  2855.  
  2856.  
  2857.  
  2858.                           -1Chapter 11 ■ Message Boxes-0
  2859.  
  2860.  
  2861.  
  2862.  
  2863.  
  2864.     A message  box is  a window  that appears  at the  center of the screen
  2865.  
  2866.     displaying a  message and  informing the  user as  to what  keys can be
  2867.  
  2868.     pressed. When an  error occurs, a  message box is  a convenient way  of
  2869.  
  2870.     informing the user about  the error. When a  choice must be made,  such
  2871.  
  2872.     as in saving changes, a message  box makes it easy to solicit  input. A
  2873.  
  2874.     close cousin to  the message box  is the message  line. A message  line
  2875.  
  2876.     is a line  of text that  flashes on the  last screen row  to inform the
  2877.  
  2878.     user that  a time-consuming  activity such  as sorting  or printing  is
  2879.  
  2880.     still   in  progress.   MSG.H   contains   the   function   prototypes.
  2881.  
  2882.  
  2883.  
  2884.     -1Prototype-0: int msg (int type, char *msg, int bdattr, int txattr);
  2885.  
  2886.  
  2887.  
  2888.     The  "msg" function  implements  a  message  box.  The  message  to  be
  2889.  
  2890.     displayed is pointed  to by "msg"  and should not  exceed 77 characters
  2891.  
  2892.     (not including the ASCII NULL  character). The video attribute used  in
  2893.  
  2894.     displaying  the border  is  passed  in "bdattr"  and the  attribute for
  2895.  
  2896.     displaying  text within  the  message  box is  passed in  "txattr". The
  2897.  
  2898.     "type" argument  can be  one of  the three  "MSG_" constants defined in
  2899.  
  2900.     MSG.H. If MSG_AB is passed  then the line "PRESS A(Above)  OR B(Below)"
  2901.  
  2902.     is displayed on  the last line  of the box.  If MSG_ANY is  passed then
  2903.  
  2904.     the line  "PRESS ANY  KEY TO  CONTINUE" is  displayed on  this line. If
  2905.  
  2906.     MSG_YN is passed  then the line  "PRESS Y(Yes) OR  N(No)" is displayed.
  2907.  
  2908.     An uppercase A or B is returned if MSG_AB is passed, an uppercase Y  or
  2909.  
  2910.     N  is returned  if  MSG_YN  is  passed.  Any keystroke  is returned  if
  2911.  
  2912.     MSG_ANY is passed. The "msg"  function saves the current cursor  shape,
  2913.  
  2914.     position and underlying screen  contents before displaying the  message
  2915.  
  2916.     box. Upon  exit, the  cursor shape,  position, and  screen contents are
  2917.  
  2918.     restored.
  2919.  
  2920.  
  2921.  
  2922.     -1Prototype-0: void msg_flash (int cmd, ...);
  2923.  
  2924.  
  2925.  
  2926.     Flash a  message on  the last  screen row.  If "cmd"  is MSG_FON then a
  2927.  
  2928.     character string  must follow  as the  second and  final argument. This
  2929.  
  2930.     string will be flashed on the bottom line using a LIGHTGRAY  attribute.
  2931.  
  2932.     If "cmd"  is MSG_FOFF  then this  is the  only argument  and the screen
  2933.  
  2934.     contents under this  flashing line will  be restored removing  the line
  2935.  
  2936.     from  the screen.  This  function  cannot be  nested because  each call
  2937.  
  2938.     using MSG_FON causes  the underlying screen  contents to be  saved in a
  2939.  
  2940.     static  buffer overwriting  the  contents  of  the  previous  call.  An
  2941.  
  2942.     intervening  call  using  MSG_FOFF  is  required  before  a  subsequent
  2943.  
  2944.     MSG_FON.
  2945.  
  2946.  
  2947.  
  2948.  
  2949.  
  2950.  
  2951.  
  2952.  
  2953.  
  2954.  
  2955.  
  2956.  
  2957.  
  2958.  
  2959.  
  2960.  
  2961.  
  2962.  
  2963.  
  2964.  
  2965.  
  2966.  
  2967.  
  2968.  
  2969.  
  2970.  
  2971.  
  2972.  
  2973.  
  2974.  
  2975.  
  2976.  
  2977.                                     - 24 -
  2978.  
  2979.  
  2980.  
  2981.  
  2982.                           -1Chapter 12 ■ Mouse Support-0
  2983.  
  2984.  
  2985.  
  2986.  
  2987.  
  2988.     The mouse has become a very important input mechanism on PC  computers.
  2989.  
  2990.     Application  programs communicate  with a  mouse via  the mouse  device
  2991.  
  2992.     driver. This driver  takes over interrupt  33 hexadecimal which  serves
  2993.  
  2994.     as the communications interface.  The functions in this  library handle
  2995.  
  2996.     all the  interface details  with this  interrupt. If  you intend to use
  2997.  
  2998.     the event  handler functions  (see Chapter  6), you  will never need to
  2999.  
  3000.     use most of  these functions. Perhaps,  in a future  version of PSK,  I
  3001.  
  3002.     will  provide a  more  indepth  look  at  the  mouse.  MOUSE.H contains
  3003.  
  3004.     function prototypes.
  3005.  
  3006.  
  3007.  
  3008.     -1Prototype-0: void mreset (MRESET *resetdata);
  3009.  
  3010.  
  3011.  
  3012.     The "mreset" function initializes  the mouse and passes  back important
  3013.  
  3014.     information to  the calling  program via  a pointer  to an  MRESET data
  3015.  
  3016.     structure. The "exists"  field is set  to zero if  no mouse driver  has
  3017.  
  3018.     been  installed. The  "nbuttons"  field  returns  the  number of  mouse
  3019.  
  3020.     buttons  (2 for  Microsoft  and  3  for  Logitech). The  internal mouse
  3021.  
  3022.     handler variables are  reset, the scope  of operation becomes  the full
  3023.  
  3024.     display, and an invisible mouse cursor  is placed on the center of  the
  3025.  
  3026.     screen. The event  handler calls this  function during installation  to
  3027.  
  3028.     reset  the  mouse  and  determine  the  presence  of  a  mouse  driver.
  3029.  
  3030.  
  3031.  
  3032.     -1Prototype-0: void mshow (void);
  3033.  
  3034.  
  3035.  
  3036.     The  "mshow" function  makes an  invisible mouse  cursor visible.  This
  3037.  
  3038.     function and the  next control an  internal flag. Each  time "mshow" is
  3039.  
  3040.     called, the  flag is  incremented. The  flag is  decremented each  time
  3041.  
  3042.     "mhide" is called.  Therefore, if "mhide"  is called two  or more times
  3043.  
  3044.     before "mshow",  "mshow" must  be called  the same  number of  times to
  3045.  
  3046.     restore  the cursor  visibility.  When  using  the  event handler,  use
  3047.  
  3048.     "e_show" instead.
  3049.  
  3050.  
  3051.  
  3052.     -1Prototype-0: void mhide (void);
  3053.  
  3054.  
  3055.  
  3056.     The  "mhide" function  makes a  visible mouse  cursor invisible.  Mouse
  3057.  
  3058.     movement  can still  occur  but  the  cursor  does not  appear. Calling
  3059.  
  3060.     "mshow" at a later time after moving the mouse will show the cursor  in
  3061.  
  3062.     a  different location.  When  using  the  event  handler, use  "e_hide"
  3063.  
  3064.     instead.
  3065.  
  3066.  
  3067.  
  3068.     -1Prototype-0: void mpos (MLOCATE *locatedata);
  3069.  
  3070.  
  3071.  
  3072.     The "mpos" function returns information  about the mouse status (via  a
  3073.  
  3074.     pointer to an  MLOCATE data structure).  The "buttonstat" field  is set
  3075.  
  3076.     to the  status of  the mouse  buttons. This  field is  set to  the same
  3077.  
  3078.     values as the "parm2" field of  the event structure for a MOUSE  event.
  3079.  
  3080.     The current mouse  position is returned  in the "col"  and "row" fields
  3081.  
  3082.     (expressed in terms of pixels).
  3083.  
  3084.  
  3085.  
  3086.     -1Prototype-0: void mmoveto (int col, int row);
  3087.  
  3088.  
  3089.  
  3090.     The "mmoveto"  function moves  the mouse  cursor to  the column and row
  3091.  
  3092.     specified by "col"  and "row". These  values are expressed  in terms of
  3093.  
  3094.     pixels.
  3095.  
  3096.  
  3097.  
  3098.  
  3099.  
  3100.  
  3101.                                     - 25 -
  3102.  
  3103.  
  3104.  
  3105.  
  3106.     -1Prototype-0: void mpressed (int button, MLOCATE *locatedata);
  3107.  
  3108.  
  3109.  
  3110.     The "mpressed" function returns the  mouse pressed status for a  button
  3111.  
  3112.     specified by "button"  (a value from  0 to 2).  The "opcount" field  of
  3113.  
  3114.     the MLOCATE  structure is  set to  the number  of times  the button has
  3115.  
  3116.     been pressed since the  last time this function  was called. A call  to
  3117.  
  3118.     this function  resets this  count to  zero. The  "buttonstat" field  is
  3119.  
  3120.     set to  the status  of the  mouse buttons.  The location  of the cursor
  3121.  
  3122.     when the button  was last pressed  is returned in  the "col" and  "row"
  3123.  
  3124.     fields.
  3125.  
  3126.  
  3127.  
  3128.     -1Prototype-0: void mreleased (int button, MLOCATE *locatedata);
  3129.  
  3130.  
  3131.  
  3132.     The  "mreleased" function  provides a  similar report.  It returns  the
  3133.  
  3134.     number of times a mouse button  has been released after it was  pressed
  3135.  
  3136.     (0 or 1) via the "opcount" field.
  3137.  
  3138.  
  3139.  
  3140.     -1Prototype-0: void mcolrange (int hmin, int hmax);
  3141.  
  3142.  
  3143.  
  3144.     The "mcolrange" function sets the  horizontal range of the cursor  to a
  3145.  
  3146.     lower  limit specified  by  "hmin"  and  an  upper  limit  specified by
  3147.  
  3148.     "hmax".  Both values  are  expressed  in pixel  positions. The  default
  3149.  
  3150.     value is the entire screen width.
  3151.  
  3152.  
  3153.  
  3154.     -1Prototype-0: void mrowrange (int vmin, int vmax);
  3155.  
  3156.  
  3157.  
  3158.     The "mrowrange"  function sets  the vertical  range of  the cursor to a
  3159.  
  3160.     lower  limit specified  by  "vmin"  and  an  upper  limit  specified by
  3161.  
  3162.     "vmax".  Both values  are  expressed  in pixel  positions. The  default
  3163.  
  3164.     value is the entire screen height.
  3165.  
  3166.  
  3167.  
  3168.     -1Prototype-0: void mgraphcursor (MGCURSOR *gcursordata);
  3169.  
  3170.  
  3171.  
  3172.     The "mgraphcursor" function defines  the mouse cursor appearance  for a
  3173.  
  3174.     mouse cursor operating  in graphics mode.  The default graphics  cursor
  3175.  
  3176.     is an  arrow pointing  in the  upper-left direction.  A data  structure
  3177.  
  3178.     (MGCURSOR)  pointed to  by  "gcursordata"  defines the  cursor via  the
  3179.  
  3180.     following fields. The  "image" field is  a pointer to  a pair or  masks
  3181.  
  3182.     defining the  cursor appearance.  Each mask  is defined  by an array of
  3183.  
  3184.     16-bit  unsigned integers.  The  first  16 define  screen mask  and the
  3185.  
  3186.     next 16 define cursor  mask. The driver will  AND the screen mask  with
  3187.  
  3188.     the display  area where  the cursor  will be  placed and  then XORs the
  3189.  
  3190.     result  with the  cursor mask.  This results  in a  cursor that  always
  3191.  
  3192.     appears in front of whatever is  on the display (even when in  front of
  3193.  
  3194.     an  object with  the  same  color). The  hot spot  is a  pixel position
  3195.  
  3196.     within the mask  that maps to  one pixel on  the display. The  hot spot
  3197.  
  3198.     is defined  relative to  the upperleft  corner of  the cursor mask. The
  3199.  
  3200.     driver  needs this  value  to  manage the  graphics cursor.  The column
  3201.  
  3202.     0-15  is placed  in  "hhot".  The  row  0-15 is  placed in  "vhot". The
  3203.  
  3204.     image  and hot  spot  info  is  needed  prior to  calling mgraphcursor.
  3205.  
  3206.  
  3207.  
  3208.  
  3209.  
  3210.  
  3211.  
  3212.  
  3213.  
  3214.  
  3215.  
  3216.  
  3217.  
  3218.  
  3219.  
  3220.  
  3221.  
  3222.  
  3223.  
  3224.  
  3225.                                     - 26 -
  3226.  
  3227.  
  3228.  
  3229.  
  3230.     -1Prototype-0: void mtextcursor (int cursortype, unsigned arg1,
  3231.  
  3232.                                  unsigned arg2);
  3233.  
  3234.  
  3235.  
  3236.     The "mtextcursor"  function is  used to  select the  type of cursor and
  3237.  
  3238.     its  appearance. The  video  adaptor's  hardware  cursor  is used  when
  3239.  
  3240.     "cursortype" is  given a  value of  one. A  software cursor  is used if
  3241.  
  3242.     zero  is passed.  The  default  is  the  software  cursor.  A  software
  3243.  
  3244.     cursor's attributes are  specified by "arg1"  and "arg2". For  a cursor
  3245.  
  3246.     specified  as a  see-through  rectange,  77ffh would  be passed  in the
  3247.  
  3248.     "arg1" parameter.  If the  cursor uses  one of  the 256  ASCII codes as
  3249.  
  3250.     its shape then 0  would be passed in  "arg1". The MSB of  "arg2" is set
  3251.  
  3252.     to  the foreground/background  attribute  byte  and the  ASCII code  is
  3253.  
  3254.     placed  in the  LSB.  For  example,  0000h  and  0718h  define  a  gray
  3255.  
  3256.     up-arrow  cursor.  A  hardware  cursor  is  simpler  to  define.  Setup
  3257.  
  3258.     "arg1" and "arg2"  as the starting  and ending scan  lines. The topmost
  3259.  
  3260.     scan line is always  zero. On a monochrome  adaptor, 12 is used  as the
  3261.  
  3262.     bottommost   scan  line.   On  other   adaptors,  this   value  is   7.
  3263.  
  3264.  
  3265.  
  3266.     -1Prototype-0: void mmotion (MMOVE *movedata);
  3267.  
  3268.  
  3269.  
  3270.     The "mmotion" function returns the net movement of the mouse (given  in
  3271.  
  3272.     mickeys   -   1/100   th   of   an   inch)   since   the   last   call.
  3273.  
  3274.  
  3275.  
  3276.     -1Prototype-0: void minsttask (unsigned mask, unsigned taskseg,
  3277.  
  3278.                                unsigned taskofs);
  3279.  
  3280.  
  3281.  
  3282.     The  "minsttask" function  installs a  mouse event  handler. The  value
  3283.  
  3284.     passed in  "mask" identifies  the events  that cause  the handler to be
  3285.  
  3286.     activated. The segment and offset  addresses of the handler are  passed
  3287.  
  3288.     in "taskseg" and "taskofs" respectively.  There is no need for  further
  3289.  
  3290.     discussion  because   the  event   handler  handles   mouse  events  by
  3291.  
  3292.     installing    a   mouse    event    handler    via    this    function.
  3293.  
  3294.  
  3295.  
  3296.     -1Prototype-0: void mlpenon (void);
  3297.  
  3298.  
  3299.  
  3300.     The  "mlpenon" function  activates  lightpen  emulation (the  default).
  3301.  
  3302.  
  3303.  
  3304.     -1Prototype-0: void mlpenoff (void);
  3305.  
  3306.  
  3307.  
  3308.     The "mlpenoff" function deactivates lightpen emulation.
  3309.  
  3310.  
  3311.  
  3312.     -1Prototype-0: void mratio (int horiz, int vert);
  3313.  
  3314.  
  3315.  
  3316.     The "mratio" function defines the  mickey to pixel ratio. Defaults  are
  3317.  
  3318.     16  for vertical  and  8  for horizontal.  This function  defines mouse
  3319.  
  3320.     sensitivity.
  3321.  
  3322.  
  3323.  
  3324.     -1Prototype-0: unsigned mbufsize (void);
  3325.  
  3326.  
  3327.  
  3328.     The "mbufsize"  function returns  the size  of the  buffer needed  when
  3329.  
  3330.     saving  the   mouse  state.   The  value   is  the   number  of  bytes.
  3331.  
  3332.  
  3333.  
  3334.     -1Prototype-0: void msave (char *buffer);
  3335.  
  3336.  
  3337.  
  3338.     The  "msave" function  saves  the  current  mouse  state  in  "buffer".
  3339.  
  3340.  
  3341.  
  3342.  
  3343.  
  3344.  
  3345.  
  3346.  
  3347.  
  3348.  
  3349.                                     - 27 -
  3350.  
  3351.  
  3352.  
  3353.  
  3354.     -1Prototype-0: void mrest (char *buffer);
  3355.  
  3356.  
  3357.  
  3358.     The "mrest"  function restores  the mouse  state from  the contents  of
  3359.  
  3360.     "buffer".
  3361.  
  3362.  
  3363.  
  3364.  
  3365.  
  3366.  
  3367.  
  3368.  
  3369.  
  3370.  
  3371.  
  3372.  
  3373.  
  3374.  
  3375.  
  3376.  
  3377.  
  3378.  
  3379.  
  3380.  
  3381.  
  3382.  
  3383.  
  3384.  
  3385.  
  3386.  
  3387.  
  3388.  
  3389.  
  3390.  
  3391.  
  3392.  
  3393.  
  3394.  
  3395.  
  3396.  
  3397.  
  3398.  
  3399.  
  3400.  
  3401.  
  3402.  
  3403.  
  3404.  
  3405.  
  3406.  
  3407.  
  3408.  
  3409.  
  3410.  
  3411.  
  3412.  
  3413.  
  3414.  
  3415.  
  3416.  
  3417.  
  3418.  
  3419.  
  3420.  
  3421.  
  3422.  
  3423.  
  3424.  
  3425.  
  3426.  
  3427.  
  3428.  
  3429.  
  3430.  
  3431.  
  3432.  
  3433.  
  3434.  
  3435.  
  3436.  
  3437.  
  3438.  
  3439.  
  3440.  
  3441.  
  3442.  
  3443.  
  3444.  
  3445.  
  3446.  
  3447.  
  3448.  
  3449.  
  3450.  
  3451.  
  3452.  
  3453.  
  3454.  
  3455.  
  3456.  
  3457.  
  3458.  
  3459.  
  3460.  
  3461.  
  3462.  
  3463.  
  3464.  
  3465.  
  3466.  
  3467.  
  3468.  
  3469.  
  3470.  
  3471.  
  3472.  
  3473.                                     - 28 -
  3474.  
  3475.  
  3476.  
  3477.  
  3478.                              -1Chapter 13 ■ Printing-0
  3479.  
  3480.  
  3481.  
  3482.  
  3483.  
  3484.     An important component  of any database  program is the  print manager.
  3485.  
  3486.     The  print manager  consists  of  a  set  of  functions  that allow  an
  3487.  
  3488.     application   to    send   information    to   the    printer   in    a
  3489.  
  3490.     printer-independent  fashion. Some  managers  also  provide  background
  3491.  
  3492.     printing although this capability has yet to be added to the PSK  print
  3493.  
  3494.     manager.  You can  send  individual  characters  or  strings containing
  3495.  
  3496.     embedded virtual control codes to  the print manager where these  codes
  3497.  
  3498.     are translated into appropriate  code sequences based on  the currently
  3499.  
  3500.     loaded printer driver  before they are  issued to the  printer. You can
  3501.  
  3502.     eject pages and determine the  number of lines that have  been printed.
  3503.  
  3504.     I will have more to save  on printer drivers and virtual control  codes
  3505.  
  3506.     in  Appendix  C  where  the  MAKEDRV  program  is  discussed.   PRINT.H
  3507.  
  3508.     contains  function prototypes  and constants  for the  LPT1, LPT2,  and
  3509.  
  3510.     LPT3  printer ports.  You  should  use  these  constants  in  place  of
  3511.  
  3512.     numbers   when  referencing   a   printer   port   in   your   program.
  3513.  
  3514.  
  3515.  
  3516.     -1Prototype-0: int p_char (int c);
  3517.  
  3518.  
  3519.  
  3520.     Send the character whose  ASCII code is contained  in "c" to the  print
  3521.  
  3522.     manager.  If a  line  feed  character is  sent then  an internal  lines
  3523.  
  3524.     printed counter is  incremented. If this  counter equals the  number of
  3525.  
  3526.     lines per page then the page  is ejected and the lines printed  counter
  3527.  
  3528.     is  reset to  zero.  If  an  error  occurs  then  ESC  is  returned. If
  3529.  
  3530.     successful then !ESC is returned.
  3531.  
  3532.  
  3533.  
  3534.     -1Prototype-0: int p_eject (void);
  3535.  
  3536.  
  3537.  
  3538.     This function is called  by "p_char" to eject  a page. It does  nothing
  3539.  
  3540.     more than send  a form feed  character to the  print manager and  reset
  3541.  
  3542.     the lines  printed counter  to zero.  If an  error occurs  then ESC  is
  3543.  
  3544.     returned.  If successful then !ESC is returned.
  3545.  
  3546.  
  3547.  
  3548.     -1Prototype-0: void p_init (int _lpp, int _port);
  3549.  
  3550.  
  3551.  
  3552.     Initialize the print  manager. The number  of lines per  page is passed
  3553.  
  3554.     in  "_lpp". This  value  is  used in  determining if  a page  should be
  3555.  
  3556.     ejected. The  printer port  is passed  in "_port".  You should  use one
  3557.  
  3558.     of  the LPT  constants  defined  in  PRINT.H  when  specifying  a port.
  3559.  
  3560.  
  3561.  
  3562.     -1Prototype-0: int p_lc (void);
  3563.  
  3564.  
  3565.  
  3566.     Return the value of the lines printed counter.
  3567.  
  3568.  
  3569.  
  3570.     -1Prototype-0: int p_loaddrv (char *_filespec);
  3571.  
  3572.  
  3573.  
  3574.     Load  a printer  driver.  A  printer driver  contains printer  specific
  3575.  
  3576.     codes and virtual codes. When a  virtual string is passed to the  print
  3577.  
  3578.     manager, it compares this string to  one of the virtual strings in  the
  3579.  
  3580.     driver.  If the  string  is  found  then  the  corresponding  string of
  3581.  
  3582.     printer specific codes is output to the printer instead of the  virtual
  3583.  
  3584.     string  allowing printer  independence  for  a program.  The drive  and
  3585.  
  3586.     path of  the driver  can be  specified as  part of  "_filespec". If  no
  3587.  
  3588.     extension is specified  then .DRV is  assumed. If an  error occurs then
  3589.  
  3590.     -1   is    returned.   If    successful   then    zero   is   returned.
  3591.  
  3592.  
  3593.  
  3594.  
  3595.  
  3596.  
  3597.                                     - 29 -
  3598.  
  3599.  
  3600.  
  3601.  
  3602.     -1Prototype-0: void p_sc (int _lp);
  3603.  
  3604.  
  3605.  
  3606.     Set  the lines  printed  counter  to  "_lp".  I  have  never used  this
  3607.  
  3608.     function    but   decided    to    include    it    just    in    case.
  3609.  
  3610.  
  3611.  
  3612.     -1Prototype-0: int p_scandrv (char **drivers);
  3613.  
  3614.  
  3615.  
  3616.     Scan the  current directory  for files  ending with  a .DRV  extension.
  3617.  
  3618.     Record their names in an internal  array and pass the addresses to  the
  3619.  
  3620.     "drivers"  array. The  array  should  be  capable  of holding  MAXDRV+1
  3621.  
  3622.     addresses. If  no .DRV  files are  found then  -1 is  returned. If more
  3623.  
  3624.     than MAXDRV  .DRV files  are found  then -2  is returned. If successful
  3625.  
  3626.     then zero is returned.
  3627.  
  3628.  
  3629.  
  3630.     -1Prototype-0: int p_stat (void);
  3631.  
  3632.  
  3633.  
  3634.     Return the current printer status (ESC or !ESC).
  3635.  
  3636.  
  3637.  
  3638.     -1Prototype-0: int p_str (char *str);
  3639.  
  3640.  
  3641.  
  3642.     Send  the string  of  characters  pointed  to  by  "str"  to the  print
  3643.  
  3644.     manager.  The string  may  contain  embedded control  codes. A  control
  3645.  
  3646.     code  begins with  a "^"  character and  is immediately  followed by  a
  3647.  
  3648.     decimal number  between 0  and 255  inclusive. An  INVALID CONTROL CODE
  3649.  
  3650.     message will be displayed if no  decimal number follows the "^" or  the
  3651.  
  3652.     decimal number  is greater  than 255.  If a  "^" is  to be  sent to the
  3653.  
  3654.     print manager then it  must be doubled (i.e.,  send "^^"). If an  error
  3655.  
  3656.     occurs  then ESC  is  returned.  If successful  then !ESC  is returned.
  3657.  
  3658.  
  3659.  
  3660.     -1Prototype-0: int p_xchar (int c, int count);
  3661.  
  3662.  
  3663.  
  3664.     Send  upto  "count"  copies  of  the  character  whose  ASCII  code  is
  3665.  
  3666.     contained  in "c"  to  the  print manager.  This may  result in  a page
  3667.  
  3668.     eject if "c" contains  a line feed code  and the lines printed  counter
  3669.  
  3670.     equals the number  of lines per  page. If an  error occurs then  ESC is
  3671.  
  3672.     returned.  If successful then !ESC is returned.
  3673.  
  3674.  
  3675.  
  3676.  
  3677.  
  3678.  
  3679.  
  3680.  
  3681.  
  3682.  
  3683.  
  3684.  
  3685.  
  3686.  
  3687.  
  3688.  
  3689.  
  3690.  
  3691.  
  3692.  
  3693.  
  3694.  
  3695.  
  3696.  
  3697.  
  3698.  
  3699.  
  3700.  
  3701.  
  3702.  
  3703.  
  3704.  
  3705.  
  3706.  
  3707.  
  3708.  
  3709.  
  3710.  
  3711.  
  3712.  
  3713.  
  3714.  
  3715.  
  3716.  
  3717.  
  3718.  
  3719.  
  3720.  
  3721.                                     - 30 -
  3722.  
  3723.  
  3724.  
  3725.  
  3726.                              -1Chapter 14 ■ Security-0
  3727.  
  3728.  
  3729.  
  3730.  
  3731.  
  3732.     File security is an important  issue in database design. Although  many
  3733.  
  3734.     databases  can be  conceived  without  security, there  are times  when
  3735.  
  3736.     security  is mandatory.  For  example,  a  company  does  not  want its
  3737.  
  3738.     payroll data easily accessible to just anyone.
  3739.  
  3740.  
  3741.  
  3742.     I spent alot of time thinking of different techniques for dealing  with
  3743.  
  3744.     security but  none seemed  satisfactory. The  technique should  be easy
  3745.  
  3746.     to  implement and  relatively  transparent  to program  operation. Most
  3747.  
  3748.     importantly,  the  technique  must  be  secure.  I  chose  a   two-fold
  3749.  
  3750.     technique to deal with security.
  3751.  
  3752.  
  3753.  
  3754.     This technique involves the creation of file read/write functions  that
  3755.  
  3756.     mirror  the standard  "fread"  and  "fwrite"  functions.  The "s_fread"
  3757.  
  3758.     function mirrors the  "fread" function except  that after data  is read
  3759.  
  3760.     from the disk, it is run  through a decoder before being passed  to the
  3761.  
  3762.     application. Similarly,  the "s_fwrite"  function mirrors  "fwrite" but
  3763.  
  3764.     encodes   information    prior   to    writing   it    to   the   disk.
  3765.  
  3766.  
  3767.  
  3768.     The  encoding algorithm  is  fairly  straightforward.  A  byte with  an
  3769.  
  3770.     ASCII code  less than  128 is  replaced by  a byte  with an  odd-number
  3771.  
  3772.     ASCII code starting at one. If  the ASCII code starts at 128  then this
  3773.  
  3774.     byte is replaced by a byte  with an even-number ASCII code starting  at
  3775.  
  3776.     zero.  Here are some examples.
  3777.  
  3778.  
  3779.  
  3780.     --------  ----------
  3781.  
  3782.     Original  Translated
  3783.  
  3784.     --------  ----------
  3785.  
  3786.  
  3787.  
  3788.       0         1
  3789.  
  3790.       1         3
  3791.  
  3792.       2         5
  3793.  
  3794.     .............
  3795.  
  3796.     125       251
  3797.  
  3798.     126       253
  3799.  
  3800.     127       255
  3801.  
  3802.     .............
  3803.  
  3804.     128         0
  3805.  
  3806.     129         2
  3807.  
  3808.     130         4
  3809.  
  3810.     .............
  3811.  
  3812.     253       250
  3813.  
  3814.     254       252
  3815.  
  3816.     255       254
  3817.  
  3818.  
  3819.  
  3820.     Each byte is run  through the encoder in  three passes. The first  pass
  3821.  
  3822.     uses the original  byte as input  to the encoder.  The output from  the
  3823.  
  3824.     encoder   is  used   as   the   input   for   the   next   two  passes.
  3825.  
  3826.  
  3827.  
  3828.     Security  is maintained  as  long  as  this  algorithm remains  secret.
  3829.  
  3830.     However, since  you now  are aware  of this  algorithm, it  cannot be a
  3831.  
  3832.     secret much longer.  You may wish  to try some  modifications to create
  3833.  
  3834.     a new secret algorithm. As  long as unauthorized persons are  not privy
  3835.  
  3836.     to the algorithm, the data  remains hidden (DEBUG, TYPE, and  other DOS
  3837.  
  3838.     commands can be used to view the  contents of the file but the data  is
  3839.  
  3840.     undecipherable).
  3841.  
  3842.  
  3843.  
  3844.  
  3845.                                     - 31 -
  3846.  
  3847.  
  3848.  
  3849.  
  3850.     Although  the hidden  algorithm  technique  elegantly  deals  with  the
  3851.  
  3852.     external  access problem,  there  remains  the  problem  of  preventing
  3853.  
  3854.     unauthorized persons  from running  the program  and viewing  data. The
  3855.  
  3856.     solution is to employ a routine to obtain the password and compare  the
  3857.  
  3858.     entered  password with  a  hidden  password before  giving access.  The
  3859.  
  3860.     password will need to be stored  as static data within the program  but
  3861.  
  3862.     it should be  stored in some  kind of modified  state so that  the user
  3863.  
  3864.     cannot peruse the file contents  and obtain the password. An  algorithm
  3865.  
  3866.     would be employed  to decode this  password dynamically. The  following
  3867.  
  3868.     functions implement my  security package. SECURITY.H  contains function
  3869.  
  3870.     prototypes.
  3871.  
  3872.  
  3873.  
  3874.     -1Prototype-0: size_t s_fread (void *ptr, size_t size, size_t n,
  3875.  
  3876.                                FILE *stream);
  3877.  
  3878.  
  3879.  
  3880.     This function  is identical  to the  "fread" function  except that  the
  3881.  
  3882.     information  is   decoded  before   being  sent   to  the  application.
  3883.  
  3884.  
  3885.  
  3886.     -1Prototype-0: size_t s_fwrite (void *ptr, size_t size, size_t n,
  3887.  
  3888.                                 FILE *stream);
  3889.  
  3890.  
  3891.  
  3892.     This function  is identical  to the  "fwrite" function  except that the
  3893.  
  3894.     information   is   encoded   before    being   sent   to   the    file.
  3895.  
  3896.  
  3897.  
  3898.     -1Prototype-0: int s_pmtpwd (char *title, char *pwd);
  3899.  
  3900.  
  3901.  
  3902.     This function  solicits a  password from  the user.  As the password is
  3903.  
  3904.     entered, asterisks appear instead of the actual characters the user  is
  3905.  
  3906.     entering.  A maximum  of  ten  characters  can  be  entered.  A  typing
  3907.  
  3908.     mistake   can   be   corrected   by   pressing   the   backspace   key.
  3909.  
  3910.  
  3911.  
  3912.     The  RETURN and  ESC keys  are used  to exit.  A beep  will sound  when
  3913.  
  3914.     RETURN is pressed  and no characters  have been entered.  This does not
  3915.  
  3916.     happen if ESC is  pressed. RETURN indicates the  user wants to try  out
  3917.  
  3918.     the entered  password and  ESC indicates  the user  wishes to  exit the
  3919.  
  3920.     program. Only  alphanumeric characters  are considered  as part  of the
  3921.  
  3922.     password.
  3923.  
  3924.  
  3925.  
  3926.  
  3927.  
  3928.  
  3929.  
  3930.  
  3931.  
  3932.  
  3933.  
  3934.  
  3935.  
  3936.  
  3937.  
  3938.  
  3939.  
  3940.  
  3941.  
  3942.  
  3943.  
  3944.  
  3945.  
  3946.  
  3947.  
  3948.  
  3949.  
  3950.  
  3951.  
  3952.  
  3953.  
  3954.  
  3955.  
  3956.  
  3957.  
  3958.  
  3959.  
  3960.  
  3961.  
  3962.  
  3963.  
  3964.  
  3965.  
  3966.  
  3967.  
  3968.  
  3969.                                     - 32 -
  3970.  
  3971.  
  3972.  
  3973.  
  3974.                            -1Chapter 15 ■ String Tools-0
  3975.  
  3976.  
  3977.  
  3978.  
  3979.  
  3980.     Although the  standard C  library contains  a variety  of useful mem...
  3981.  
  3982.     and str... functions, I needed to  invent a few new functions to  solve
  3983.  
  3984.     certain  problems.  STR.H  contains  prototypes  for  these  functions.
  3985.  
  3986.  
  3987.  
  3988.     -1Prototype-0: void memswap (void *addr1, void *addr2, unsigned n);
  3989.  
  3990.  
  3991.  
  3992.     In order to create an efficient sort algorithm for sorting any kind  of
  3993.  
  3994.     data, I needed a generic  function for swapping individual elements  of
  3995.  
  3996.     this  data.  The  "memswap"   function  views  memory  as   an  untyped
  3997.  
  3998.     collection  of bytes.  By  using  casts,  the  addresses  of  two  data
  3999.  
  4000.     elements being swapped are passed via "addr1" and "addr2" and the  size
  4001.  
  4002.     of an individual element (in bytes)  via "n". The C sizeof operator  is
  4003.  
  4004.     useful for calculating the size at compile time.
  4005.  
  4006.  
  4007.  
  4008.     -1Prototype-0: char *_strcjust (char *str, int slen);
  4009.  
  4010.  
  4011.  
  4012.     Center justify the string "str"  by adjusting the leading and  trailing
  4013.  
  4014.     spaces until it is "slen"  characters long with the text  centered. The
  4015.  
  4016.     string must  have room  for at  least "slen"+1  characters. The address
  4017.  
  4018.     of "str" is returned.
  4019.  
  4020.  
  4021.  
  4022.     -1Prototype-0: char *_strljust (char *str, int slen);
  4023.  
  4024.  
  4025.  
  4026.     Left justify the  string "str" by  removing leading spaces  and padding
  4027.  
  4028.     with  spaces on  the  right  until it  is "slen"  characters long.  The
  4029.  
  4030.     string must  have room  for at  least "slen"+1  characters. The address
  4031.  
  4032.     of "str" is returned.
  4033.  
  4034.  
  4035.  
  4036.     -1Prototype-0: char *_strltrm (char *str);
  4037.  
  4038.  
  4039.  
  4040.     Trim trailing  spaces from  the string  "str". The  address of "str" is
  4041.  
  4042.     returned.
  4043.  
  4044.  
  4045.  
  4046.     -1Prototype-0: char *_strpad (char *str, int slen);
  4047.  
  4048.  
  4049.  
  4050.     Pad a string "str" with spaces on the right until it is exactly  "slen"
  4051.  
  4052.     characters in length. The string  must have room for at  least "slen"+1
  4053.  
  4054.     characters.  The address of "str" is returned.
  4055.  
  4056.  
  4057.  
  4058.     -1Prototype-0: char *_strrjust (char *str, int slen);
  4059.  
  4060.  
  4061.  
  4062.     Right justify the string "str" by removing trailing spaces and  padding
  4063.  
  4064.     with  spaces on  the  left  until  it  is "slen"  characters long.  The
  4065.  
  4066.     string must  have room  for at  least "slen"+1  characters. The address
  4067.  
  4068.     of "str" is returned.
  4069.  
  4070.  
  4071.  
  4072.     -1Prototype-0: char *_strtrm (char *str);
  4073.  
  4074.  
  4075.  
  4076.     Trim leading  spaces from  the string  "str". The  address of  "str" is
  4077.  
  4078.     returned.
  4079.  
  4080.  
  4081.  
  4082.  
  4083.  
  4084.  
  4085.  
  4086.  
  4087.  
  4088.  
  4089.  
  4090.  
  4091.  
  4092.  
  4093.                                     - 33 -
  4094.  
  4095.  
  4096.  
  4097.  
  4098.     -1Prototype-0: char *_strxcat (char *dest, char *src, ...);
  4099.  
  4100.  
  4101.  
  4102.     Concatenate one  or more  strings in  a single  operation. At least one
  4103.  
  4104.     source  string (pointed  to  by  "src")  must  be  specified.  As  many
  4105.  
  4106.     strings  as necessary  can  follow  "src".  The  last  string  must  be
  4107.  
  4108.     followed  by NULL.  The  contents  of  these  strings are  stored in  a
  4109.  
  4110.     string pointed  to by  "dest". The  target string  must be large enough
  4111.  
  4112.     to   hold  the   result.   The   address   of   "dest"   is   returned.
  4113.  
  4114.  
  4115.  
  4116.     Example:
  4117.  
  4118.  
  4119.  
  4120.     #include <stdio.H>
  4121.  
  4122.     #include <string.H>
  4123.  
  4124.  
  4125.  
  4126.     #include "str.H"
  4127.  
  4128.  
  4129.  
  4130.     void main (void)
  4131.  
  4132.     {
  4133.  
  4134.        int stars_len;
  4135.  
  4136.        char *hello = "HELLO";
  4137.  
  4138.        char *world = "WORLD";
  4139.  
  4140.        char *stars = "***************************************";
  4141.  
  4142.        char title [80];
  4143.  
  4144.  
  4145.  
  4146.        (void) _strxcat (title, hello, " ", world, NULL);
  4147.  
  4148.  
  4149.  
  4150.        puts (stars);
  4151.  
  4152.        puts (_strljust (title, stars_len = strlen (stars)));
  4153.  
  4154.        puts (_strcjust (title, stars_len));
  4155.  
  4156.        puts (_strrjust (title, stars_len));
  4157.  
  4158.        puts (stars);
  4159.  
  4160.     }
  4161.  
  4162.  
  4163.  
  4164.  
  4165.  
  4166.  
  4167.  
  4168.  
  4169.  
  4170.  
  4171.  
  4172.  
  4173.  
  4174.  
  4175.  
  4176.  
  4177.  
  4178.  
  4179.  
  4180.  
  4181.  
  4182.  
  4183.  
  4184.  
  4185.  
  4186.  
  4187.  
  4188.  
  4189.  
  4190.  
  4191.  
  4192.     
  4193.  
  4194.  
  4195.  
  4196.  
  4197.  
  4198.  
  4199.  
  4200.  
  4201.  
  4202.  
  4203.  
  4204.  
  4205.  
  4206.  
  4207.  
  4208.  
  4209.  
  4210.  
  4211.  
  4212.  
  4213.  
  4214.  
  4215.  
  4216.  
  4217.                                     - 34 -
  4218.  
  4219.  
  4220.  
  4221.  
  4222.                            -1Chapter 16 ■ System Query-0
  4223.  
  4224.  
  4225.  
  4226.  
  4227.  
  4228.     The ability to check the current state of a computer is crucial to  the
  4229.  
  4230.     proper  operation of  applications.  For  example, an  application that
  4231.  
  4232.     uses graphics needs  to know what  kind of video  adaptor is available.
  4233.  
  4234.     As  another example,  an  application  designed  to  defragment a  disk
  4235.  
  4236.     should not run if Microsoft  Windows is active. This chapter  describes
  4237.  
  4238.     the  system query  or  "sq"  functions present  in PSK  version 1.3.  A
  4239.  
  4240.     video adaptor  query function  can be  found in  the next chapter which
  4241.  
  4242.     deals with video.  SQ.H contains function prototypes.
  4243.  
  4244.  
  4245.  
  4246.     -1Prototype-0: int sq_dos1 (void);
  4247.  
  4248.  
  4249.  
  4250.     Determine if  DOS version  1.x is  active. A  nonzero value is returned
  4251.  
  4252.     if   version    1.x   is    active   otherwise    zero   is   returned.
  4253.  
  4254.  
  4255.  
  4256.     -1Prototype-0: int sq_dos5 (void);
  4257.  
  4258.  
  4259.  
  4260.     Determine if DOS  version 5.0 or  higher is active.  DOS 5.0 introduced
  4261.  
  4262.     the SETVER command which allows users  to tell DOS to "lie" to  certain
  4263.  
  4264.     applications.  These applications  are  "fooled"  into "thinking"  that
  4265.  
  4266.     they are running under a previous version of DOS when in fact they  are
  4267.  
  4268.     running under  version 5.0  or higher.  This function  is not "fooled".
  4269.  
  4270.     A  nonzero value  is  returned  if  version  5.0  or  higher is  active
  4271.  
  4272.     otherwise zero is returned.
  4273.  
  4274.  
  4275.  
  4276.     -1Prototype-0: int sq_dvact (void);
  4277.  
  4278.  
  4279.  
  4280.     This function returns a nonzero value if Desqview version 2.0 or  later
  4281.  
  4282.     is  active otherwise  zero  is  returned. A  robust application  should
  4283.  
  4284.     check for this possibility if there is the chance that the  application
  4285.  
  4286.     will fail when Desqview is active.
  4287.  
  4288.  
  4289.  
  4290.     -1Prototype-0: int sq_winact (void);
  4291.  
  4292.  
  4293.  
  4294.     This  function returns  1 if  Windows is  running in  real or  standard
  4295.  
  4296.     mode, 2 if Windows is running in 386-enhanced mode, or 0 if Windows  is
  4297.  
  4298.     not running. If there is  the possiblity that an application  will fail
  4299.  
  4300.     when Windows is running then  the application should use this  function
  4301.  
  4302.     to check if Windows is active.
  4303.  
  4304.  
  4305.  
  4306.     -1Prototype-0: int sq_xmm (void);
  4307.  
  4308.  
  4309.  
  4310.     This function allows an application to determine if an extended  memory
  4311.  
  4312.     manager (such as HIMEM.SYS) is  active. A nonzero value is  returned if
  4313.  
  4314.     the XMM is active otherwise zero is returned.
  4315.  
  4316.  
  4317.  
  4318.  
  4319.  
  4320.  
  4321.  
  4322.  
  4323.  
  4324.  
  4325.  
  4326.  
  4327.  
  4328.  
  4329.  
  4330.  
  4331.  
  4332.  
  4333.  
  4334.  
  4335.  
  4336.  
  4337.  
  4338.  
  4339.  
  4340.  
  4341.                                     - 35 -
  4342.  
  4343.  
  4344.  
  4345.  
  4346.                               -1Chapter 17 ■ Video-0
  4347.  
  4348.  
  4349.  
  4350.  
  4351.  
  4352.     Perhaps the  most important  component of  any computer  program is the
  4353.  
  4354.     user-interface. We  have already  examined the  PSK keyboard  interface
  4355.  
  4356.     in Chapter 9  and now it  is time to  look at the  video interface. The
  4357.  
  4358.     VIDEO module  has been  designed to  handle text-based  video modes  as
  4359.  
  4360.     opposed to graphics-based.  An 80-column screen  by 25, 43,  or 50 rows
  4361.  
  4362.     is  expected (you  need  an  EGA  adaptor  to work  with 43  rows or  a
  4363.  
  4364.     VGA/SVGA  adaptor to  work  with  50  rows).  The  MDA,  CGA, EGA,  and
  4365.  
  4366.     VGA/SVGA video standards are supported.
  4367.  
  4368.     
  4369.  
  4370.     One  problem  associated  with  the  "ancient"  CGA  adaptor  is  video
  4371.  
  4372.     interference  that arises  when  the  video  circuitry  accesses  video
  4373.  
  4374.     memory at the  same time that  the CPU is  accessing this memory.  This
  4375.  
  4376.     interference is  commonly known  as "snow".  Most computers  these days
  4377.  
  4378.     contain VGA or SVGA adaptors  although EGA is undoubtedly used  on many
  4379.  
  4380.     as well.  Snow is  not much  of an  issue anymore.  I did  not add  any
  4381.  
  4382.     snow-removal  logic to  those  video  functions that  interact directly
  4383.  
  4384.     with  video display  memory  because  this would  have slowed  down the
  4385.  
  4386.     video  system considerably  and  increased  the  size  of this  module.
  4387.  
  4388.     However, for those  of you with  CGA adaptors, the  following code will
  4389.  
  4390.     interest  you. This  code  can  be used  to provide  snow removal.  You
  4391.  
  4392.     will need  the source  code to  make these  changes (another  reason to
  4393.  
  4394.     register your copy of PSK).
  4395.  
  4396.  
  4397.  
  4398.     The MDA and CGA adaptors  contain an integrated circuit referred  to as
  4399.  
  4400.     the 6845 CRT  controller. This chip  has been emulated  by the EGA  and
  4401.  
  4402.     VGA/SVGA adaptors so  the discussion is  relevant to these  adaptors as
  4403.  
  4404.     well. The 6845  contains several internal  registers that are  accessed
  4405.  
  4406.     by using the CPU IN and OUT instructions and specifying a port  address
  4407.  
  4408.     that roughly corresponds  to a register.  The port address  03bah (MDA)
  4409.  
  4410.     or  03dah (all  other  adaptors)  is directly  connected to  the STATUS
  4411.  
  4412.     register. The  least significant  bit of  this register  (bit 0) is set
  4413.  
  4414.     to 1 if it is ok to access video memory or 0 if the video circuitry  is
  4415.  
  4416.     accessing  video memory.  This  bit  is referred  to as  the horizontal
  4417.  
  4418.     retrace  bit  because  it  is  a  reflection  of  the  video  circuitry
  4419.  
  4420.     horizontal retrace status. The  following code segment illustrates  how
  4421.  
  4422.     to  monitor the  horizontal retrace  bit in  order to  avoid snow.  The
  4423.  
  4424.     code segment assumes that DX  contains 03bah and AH contains  the video
  4425.  
  4426.     attribute.
  4427.  
  4428.  
  4429.  
  4430.  
  4431.  
  4432.  
  4433.  
  4434.  
  4435.  
  4436.  
  4437.  
  4438.  
  4439.  
  4440.  
  4441.  
  4442.  
  4443.  
  4444.  
  4445.  
  4446.  
  4447.  
  4448.  
  4449.  
  4450.  
  4451.  
  4452.  
  4453.  
  4454.  
  4455.  
  4456.  
  4457.  
  4458.  
  4459.  
  4460.  
  4461.  
  4462.  
  4463.  
  4464.  
  4465.                                     - 36 -
  4466.  
  4467.  
  4468.  
  4469.  
  4470.     @@1:
  4471.  
  4472.          lodsb               ; load next string character
  4473.  
  4474.          cmp       al, 0     ; end of string?
  4475.  
  4476.          jz        @@5       ; yes, exit loop
  4477.  
  4478.  
  4479.  
  4480.          cli                 ; interrupts must be disabled
  4481.  
  4482.          push      ax
  4483.  
  4484.     @@2:
  4485.  
  4486.          in        al, dx    ; wait out current horizontal retrace
  4487.  
  4488.          shr       al, 1     ; there may not be enough time left
  4489.  
  4490.          jc        @@2
  4491.  
  4492.     @@3:
  4493.  
  4494.          in        al, dx    ; wait for next horizontal retrace
  4495.  
  4496.          shr       al, 1
  4497.  
  4498.          jnc       @@3
  4499.  
  4500.     @@4:
  4501.  
  4502.          pop       ax
  4503.  
  4504.          stosw               ; go ahead and write character
  4505.  
  4506.          sti                 ; reenable interrupts
  4507.  
  4508.          jmp       SHORT @@1
  4509.  
  4510.     @@5:
  4511.  
  4512.  
  4513.  
  4514.     VIDEO.H contains  function prototypes  along with  many useful contants
  4515.  
  4516.     and  macros. The  screen  coordinate  system  has  been  setup  so that
  4517.  
  4518.     columns range from 1 to 80 and rows from 1 to 25, 1 to 43, or 1 to  50.
  4519.  
  4520.  
  4521.  
  4522.     -1Prototype-0: int v_aa (void);
  4523.  
  4524.  
  4525.  
  4526.     Identify  the active  video  adaptor.  In  the  case  of  EGA  and  VGA
  4527.  
  4528.     adaptors, "v_aa" also identifies the  kind of monitor connected to  the
  4529.  
  4530.     computer  (black &  white or  color). One  of the  constants MDA,  CGA,
  4531.  
  4532.     EGA_BW, EGA_COLOR, VGA_BW, or VGA_COLOR is returned.
  4533.  
  4534.  
  4535.  
  4536.     -1Prototype-0: int v_attr (char *str, int *attr);
  4537.  
  4538.  
  4539.  
  4540.     Display an attribute table and allow the user to select an  appropriate
  4541.  
  4542.     attribute.  The  UP  and  DOWN  arrow  keys  are  used  to  select  the
  4543.  
  4544.     background portion  of the  attribute. The  LEFT and  RIGHT arrow  keys
  4545.  
  4546.     are used  to select  the foreground  portion. The  string pointed to by
  4547.  
  4548.     "str" is displayed within  a window and the  color in which it  appears
  4549.  
  4550.     changes  as the  arrow  keys  are  used  to select  different attribute
  4551.  
  4552.     combinations. The  length of  this string  should be  such that it fits
  4553.  
  4554.     within the window. There  is no word wrapping.  If RET is pressed  then
  4555.  
  4556.     "v_attr" exits with  the appropriate attribute  returned in "attr".  If
  4557.  
  4558.     ESC  is  pressed  then  "v_attr"  exits  without  saving  the  selected
  4559.  
  4560.     attribute.  RET or ESC is returned.
  4561.  
  4562.  
  4563.  
  4564.     -1Prototype-0: void v_border (int style, int x, int y, int nx, int ny);
  4565.  
  4566.  
  4567.  
  4568.     Draw  a rectangular  border  on  the screen.  The upper-left  corner is
  4569.  
  4570.     defined by the  "x" and "y"  arguments where "x"  refers to the  column
  4571.  
  4572.     and "y" to  the row. The  internal dimensions are  defined by the  "nx"
  4573.  
  4574.     and "ny" arguments where "nx" refers to the number of columns and  "ny"
  4575.  
  4576.     refers to  the number  of rows.  The "style"  argument is  given one of
  4577.  
  4578.     the  defined   constants  SINGLE_LINE,   DOUBLE_LINE,  BLOCK_LINE,   or
  4579.  
  4580.     NOBORDER.  NOBORDER is  used  in  certain applications  that deal  with
  4581.  
  4582.     windows.
  4583.  
  4584.  
  4585.  
  4586.  
  4587.  
  4588.  
  4589.                                     - 37 -
  4590.  
  4591.  
  4592.  
  4593.  
  4594.     -1Prototype-0: void v_cleanup (void);
  4595.  
  4596.  
  4597.  
  4598.     Restore  the screen  to  an  appropriate  state  prior  to  exitting  a
  4599.  
  4600.     program.  The number  of  screen  rows  is  set  to  25, the  screen is
  4601.  
  4602.     cleared to LIGHTGRAY, the cursor is  homed, and the cursor is set  to a
  4603.  
  4604.     thin line.
  4605.  
  4606.  
  4607.  
  4608.     -1Prototype-0: int v_cputs (const char *str);
  4609.  
  4610.  
  4611.  
  4612.     This function is  similar to the  Borland "cputs" function.  The string
  4613.  
  4614.     pointed  to by  "str"  is  displayed  starting  at  the  current cursor
  4615.  
  4616.     position and using  the current video  attribute. No control  codes are
  4617.  
  4618.     translated. The ASCII code of  the last written character is  returned.
  4619.  
  4620.  
  4621.  
  4622.     -1Prototype-0: void v_cursor (int cmd, ...);
  4623.  
  4624.  
  4625.  
  4626.     The "v_cursor" function is used  for defining the cursor shape,  saving
  4627.  
  4628.     and restoring the cursor shape, and defining an alternate function  for
  4629.  
  4630.     handling these  operations should  this function  not work  on a  given
  4631.  
  4632.     video adaptor.
  4633.  
  4634.  
  4635.  
  4636.     1. v_cursor (CBLOCK);
  4637.  
  4638.  
  4639.  
  4640.     The CBLOCK command creates a block cursor shape.
  4641.  
  4642.  
  4643.  
  4644.     2. v_cursor (CHIDE);
  4645.  
  4646.  
  4647.  
  4648.     The CHIDE command hides the cursor.
  4649.  
  4650.  
  4651.  
  4652.     3. v_cursor (CLINE);
  4653.  
  4654.  
  4655.  
  4656.     The CLINE command creates a line cursor shape.
  4657.  
  4658.  
  4659.  
  4660.     4. v_cursor (CSAVE, &cshape);
  4661.  
  4662.  
  4663.  
  4664.     The  CSAVE command  saves  the  current  cursor  shape  to  the integer
  4665.  
  4666.     variable cshape.
  4667.  
  4668.  
  4669.  
  4670.     5. v_cursor (CRESTORE, cshape);
  4671.  
  4672.  
  4673.  
  4674.     The   CRESTORE  command   restores   the   cursor   shape   to  cshape.
  4675.  
  4676.  
  4677.  
  4678.     6. v_cursor (CSETFUNC, func, cmdlist);
  4679.  
  4680.  
  4681.  
  4682.     The CSETFUNC command installs a function called by "v_cursor" when  any
  4683.  
  4684.     of a combination  of commands are  passed. The following  code fragment
  4685.  
  4686.     illustrates.
  4687.  
  4688.  
  4689.  
  4690.  
  4691.  
  4692.  
  4693.  
  4694.  
  4695.  
  4696.  
  4697.  
  4698.  
  4699.  
  4700.  
  4701.  
  4702.  
  4703.  
  4704.  
  4705.  
  4706.  
  4707.  
  4708.  
  4709.  
  4710.  
  4711.  
  4712.  
  4713.                                     - 38 -
  4714.  
  4715.  
  4716.  
  4717.  
  4718.     void cursor (int cmd, ...);
  4719.  
  4720.  
  4721.  
  4722.     ...
  4723.  
  4724.  
  4725.  
  4726.     v_cursor (CSETFUNC, cursor, CHIDE | CLINE);
  4727.  
  4728.  
  4729.  
  4730.     ...
  4731.  
  4732.  
  4733.  
  4734.     void cursor (int cmd, ...)
  4735.  
  4736.     {
  4737.  
  4738.        if (cmd == CHIDE)
  4739.  
  4740.            v_setshape (config.chshape);
  4741.  
  4742.        else
  4743.  
  4744.            ...
  4745.  
  4746.     }
  4747.  
  4748.  
  4749.  
  4750.     -1Prototype-0: int v_getattr (void);
  4751.  
  4752.  
  4753.  
  4754.     Return the current video attribute.
  4755.  
  4756.  
  4757.  
  4758.     -1Prototype-0: int v_getch (void);
  4759.  
  4760.  
  4761.  
  4762.     Return the  ASCII character  code for  the character  displayed at  the
  4763.  
  4764.     current cursor position.
  4765.  
  4766.  
  4767.  
  4768.     -1Prototype-0: int v_getmode (void);
  4769.  
  4770.  
  4771.  
  4772.     Return the current video mode.
  4773.  
  4774.  
  4775.  
  4776.     -1Prototype-0: int v_getrows (void);
  4777.  
  4778.  
  4779.  
  4780.     Return the number  of screen rows.  This value defaults  to 25 but  can
  4781.  
  4782.     be  changed  with  a  call  to  "v_setrows".  Several  functions   call
  4783.  
  4784.     "v_getrows" to determine the vertical  screen size. This makes it  easy
  4785.  
  4786.     to adapt these  functions to EGA/VGA  adaptors with different  vertical
  4787.  
  4788.     sizes.
  4789.  
  4790.  
  4791.  
  4792.     -1Prototype-0: int v_getshape (void);
  4793.  
  4794.  
  4795.  
  4796.     Return the current cursor shape.  This function should only be  used in
  4797.  
  4798.     functions  attached to  "v_cursor"  for  portability  reasons.  Use the
  4799.  
  4800.     CSAVE   command   with   "v_cursor"   to   save   the   cursor   shape.
  4801.  
  4802.  
  4803.  
  4804.     -1Prototype-0: void v_gotoxy (int x, int y);
  4805.  
  4806.  
  4807.  
  4808.     Position  the cursor  to  the  column  specified  by  "x"  and the  row
  4809.  
  4810.     specified by  "y". The  column should  range from  1 to  80 and the row
  4811.  
  4812.     from 1 to the number of screen rows.
  4813.  
  4814.  
  4815.  
  4816.     -1Prototype-0: void v_paint (int c, int x, int y, int nx, int ny);
  4817.  
  4818.  
  4819.  
  4820.     Paint a rectangular  region with upper-left  corner defined by  "x" and
  4821.  
  4822.     "y" and  dimensions defined  by "nx"  and "ny".  The region  is painted
  4823.  
  4824.     using the character whose  ASCII code is in  "c" and using the  current
  4825.  
  4826.     video  attribute. The  "v_clear"  macro  uses the  space character  for
  4827.  
  4828.     clearing a region.
  4829.  
  4830.  
  4831.  
  4832.  
  4833.  
  4834.  
  4835.  
  4836.  
  4837.                                     - 39 -
  4838.  
  4839.  
  4840.  
  4841.  
  4842.     -1Prototype-0: int v_putch (int c, int count);
  4843.  
  4844.  
  4845.  
  4846.     Put  a character  whose ASCII  code is  contained in  "c" upto  "count"
  4847.  
  4848.     times on the screen starting  at the current cursor position  and using
  4849.  
  4850.     the  current video  attribute.  The  ASCII  code  for "c"  is returned.
  4851.  
  4852.  
  4853.  
  4854.     -1Prototype-0: int v_putcha (int *ca, int szca);
  4855.  
  4856.  
  4857.  
  4858.     This function displays a character/attribute buffer pointed to by  "ca"
  4859.  
  4860.     that contains "szca"  entries. Therefore, the  buffer does not  need to
  4861.  
  4862.     be  NULL terminated.  Each entry  is composed  of an  attribute in  the
  4863.  
  4864.     most  significant  byte  and  a  character  ASCII  code  in  the  least
  4865.  
  4866.     significant  byte.   The  value   contained  in   "szca"  is  returned.
  4867.  
  4868.  
  4869.  
  4870.     -1Prototype-0: void v_screen (int cmd, int x, int y, int nx, int ny,
  4871.  
  4872.                               void *buffer);
  4873.  
  4874.  
  4875.  
  4876.     Save or  restore the  screen contents.  The region  of interest  has an
  4877.  
  4878.     upper-left corner  defined by  "x" and  "y" and  dimensions defined  by
  4879.  
  4880.     "nx"  and  "ny".  The  SCREEN_SAVE  constant  is  passed  in  "cmd"  to
  4881.  
  4882.     indicate that  the region  is to  be saved  in "buffer". SCREEN_RESTORE
  4883.  
  4884.     indicates that  the contents  of "buffer"  are to  be displayed  on the
  4885.  
  4886.     screen.  The buffer  must  be  large enough  to accomodate  "nx"*"ny"*2
  4887.  
  4888.     characters.
  4889.  
  4890.  
  4891.  
  4892.     -1Prototype-0: void v_scroll (int x, int y, int nx, int ny, int dir,
  4893.  
  4894.                               int nblines, int attr);
  4895.  
  4896.  
  4897.  
  4898.     Scroll a rectangular region with  upper-left corner defined by "x"  and
  4899.  
  4900.     "y" and dimensions defined  by "nx" and "ny"  up or down by  the number
  4901.  
  4902.     of  lines specified  by  "nblines".  SCROLL_UP is  passed via  "dir" to
  4903.  
  4904.     scroll lines  upward. SCROLL_DN  causes lines  to scroll  downward. The
  4905.  
  4906.     video attribute  used in  displayed blank  lines is  passed in  "attr".
  4907.  
  4908.  
  4909.  
  4910.     -1Prototype-0: void v_setattr (int attr);
  4911.  
  4912.  
  4913.  
  4914.     Set  the current  video  attribute  to  the  contents  of  "attr".  The
  4915.  
  4916.     "v_border",  "v_cputs", "v_paint",  and "v_putch",  functions use  this
  4917.  
  4918.     attribute.
  4919.  
  4920.  
  4921.  
  4922.     -1Prototype-0: void v_setmode (int mode);
  4923.  
  4924.  
  4925.  
  4926.     Set  the current  video  mode.  Since the  video package  supports text
  4927.  
  4928.     modes only, it is recommended that you use only those modes defined  by
  4929.  
  4930.     constants BW80, C80, and MONO.
  4931.  
  4932.  
  4933.  
  4934.     -1Prototype-0: void v_setrows (int _rows);
  4935.  
  4936.  
  4937.  
  4938.     Specify the number of screen rows.  Currently, only 25, 43, and 50  can
  4939.  
  4940.     be  passed in  "_rows". All  other values  are ignored.  The screen  is
  4941.  
  4942.     set to the specified number of rows and the video system makes the  new
  4943.  
  4944.     row size  available to  all functions  that call  "v_getrows". If 43 is
  4945.  
  4946.     passed and  a VGA/SVGA  adaptor is  active then  50 is used. Similarly,
  4947.  
  4948.     if  50 is  passed  and  an  EGA  adaptor  is  active then  43 is  used.
  4949.  
  4950.  
  4951.  
  4952.  
  4953.  
  4954.  
  4955.  
  4956.  
  4957.  
  4958.  
  4959.  
  4960.  
  4961.                                     - 40 -
  4962.  
  4963.  
  4964.  
  4965.  
  4966.     -1Prototype-0: void v_setshape (int shape);
  4967.  
  4968.  
  4969.  
  4970.     Set the cursor shape to  the contents of "shape". This  function should
  4971.  
  4972.     only  be used  in  functions  attached  to  "v_cursor" for  portability
  4973.  
  4974.     reasons. Use the CBLOCK, CHIDE,  and CLINE commands with "v_cursor"  to
  4975.  
  4976.     change the cursor shape.
  4977.  
  4978.  
  4979.  
  4980.     -1Prototype-0: int v_setup (int _rows);
  4981.  
  4982.  
  4983.  
  4984.     Ensure  that the  video  mode  is either  BW80, C80,  or MONO.  Set the
  4985.  
  4986.     number  of screen  rows  to  25,  43,  or 50  as specified  by "_rows".
  4987.  
  4988.     Return the new video mode.
  4989.  
  4990.  
  4991.  
  4992.     -1Prototype-0: void v_shadow (int x1, int y1, int nx, int ny);
  4993.  
  4994.  
  4995.  
  4996.     Draw a shadow  around a rectangular  region whose upper-left  corner is
  4997.  
  4998.     specified  by "x1"  and  "y1"  and dimensions  by "nx"  and "ny".  This
  4999.  
  5000.     gives windows a 3D effect.
  5001.  
  5002.  
  5003.  
  5004.     -1Prototype-0: int v_wherex (void);
  5005.  
  5006.  
  5007.  
  5008.     Return the current cursor column.
  5009.  
  5010.  
  5011.  
  5012.     -1Prototype-0: int v_wherey (void);
  5013.  
  5014.  
  5015.  
  5016.     Return the current cursor row.
  5017.  
  5018.  
  5019.  
  5020.  
  5021.  
  5022.  
  5023.  
  5024.  
  5025.  
  5026.  
  5027.  
  5028.  
  5029.  
  5030.  
  5031.  
  5032.  
  5033.  
  5034.  
  5035.  
  5036.  
  5037.  
  5038.  
  5039.  
  5040.  
  5041.  
  5042.  
  5043.  
  5044.  
  5045.  
  5046.  
  5047.  
  5048.  
  5049.  
  5050.  
  5051.  
  5052.  
  5053.  
  5054.  
  5055.  
  5056.  
  5057.  
  5058.  
  5059.  
  5060.  
  5061.  
  5062.  
  5063.  
  5064.  
  5065.  
  5066.  
  5067.  
  5068.  
  5069.  
  5070.  
  5071.  
  5072.  
  5073.  
  5074.  
  5075.  
  5076.  
  5077.  
  5078.  
  5079.  
  5080.  
  5081.  
  5082.  
  5083.  
  5084.  
  5085.                                     - 41 -
  5086.  
  5087.  
  5088.  
  5089.  
  5090.                        -1Appendix A ■ Dealing With Errors-0
  5091.  
  5092.  
  5093.  
  5094.  
  5095.  
  5096.     What  is an  error? My  definition is  simple. An  error is  a flaw.  A
  5097.  
  5098.     compiler generates an error due to  a flaw in the syntax of  the source
  5099.  
  5100.     code. A program  generates an error  through some undesirable  behavior
  5101.  
  5102.     such as locking up  the computer due to  a flaw in its  design. I would
  5103.  
  5104.     like   to  consider   three   sources   for   these   program   errors.
  5105.  
  5106.  
  5107.  
  5108.     The first  source occurs  when invalid  data is  passed to  a function.
  5109.  
  5110.     For example, you decided to save the entire screen contents by  calling
  5111.  
  5112.     the "v_screen"  function and  passing it  the address  of a buffer that
  5113.  
  5114.     can hold  2000 characters.  The buffer  should actually  be capable  of
  5115.  
  5116.     holding   4000  characters   since   the   screen   is   divided   into
  5117.  
  5118.     character/attribute pairs  and each  pair occupies  two characters.  If
  5119.  
  5120.     you are lucky, nothing  serious will happen. However,  strange behavior
  5121.  
  5122.     will undoubtedly  occur. Very  little in  the way  of argument checking
  5123.  
  5124.     is performed by the PSK functions and there is a good reason for  this.
  5125.  
  5126.     Argument checking takes time and can  slow down a program. It can  also
  5127.  
  5128.     add to  the size  of a  program. If  you are  careful about the kind of
  5129.  
  5130.     data  passed via  function  arguments  then no  problems will  arise. I
  5131.  
  5132.     have tried to point this out  as each function in the library  has been
  5133.  
  5134.     described.  Your  best  bet  however  is  to  order  the  source  code.
  5135.  
  5136.  
  5137.  
  5138.     The  second source  comes  from  not  paying  close  attention  to file
  5139.  
  5140.     input/output return values and  not properly closing files.  You should
  5141.  
  5142.     always  check the  return value  when opening  a file,  reading from  a
  5143.  
  5144.     file, and writing to a file.  If the number of characters written  does
  5145.  
  5146.     not correspond to  the number requested  then something has  gone wrong
  5147.  
  5148.     (probably the  disk is  full). Never  exit a  function before closing a
  5149.  
  5150.     file. This may seem like common  sense but there are occasions where  I
  5151.  
  5152.     have spent alot of time trying  to track down a mysterious bug  only to
  5153.  
  5154.     find that it arose  as a result of  not properly closing a  file or not
  5155.  
  5156.     checking a return value.
  5157.  
  5158.  
  5159.  
  5160.     The third  source deals  with dynamic  memory allocation.  Never assume
  5161.  
  5162.     that  the allocation  will  succeed.  It  may  return  a  NULL pointer.
  5163.  
  5164.     Trying to  write data  to a  NULL pointer  is a  sure way to crash your
  5165.  
  5166.     program and reset the computer.
  5167.  
  5168.  
  5169.  
  5170.     I hope  you find  this information  useful when  writing programs  with
  5171.  
  5172.     PSK.    Undoubtedly,   it    will    save    you    alot    of   grief.
  5173.  
  5174.  
  5175.  
  5176.  
  5177.  
  5178.  
  5179.  
  5180.  
  5181.  
  5182.  
  5183.  
  5184.  
  5185.  
  5186.  
  5187.  
  5188.  
  5189.  
  5190.  
  5191.  
  5192.  
  5193.  
  5194.  
  5195.  
  5196.  
  5197.  
  5198.  
  5199.  
  5200.  
  5201.  
  5202.  
  5203.  
  5204.  
  5205.  
  5206.  
  5207.  
  5208.  
  5209.                                     - 42 -
  5210.  
  5211.  
  5212.  
  5213.  
  5214.                       -1Appendix B ■ DBASE III+ File Format-0
  5215.  
  5216.  
  5217.  
  5218.  
  5219.  
  5220.     The DBASE  DBF file  format is  widely used  by many database products.
  5221.  
  5222.     This  appendix provides  the  file  format  for  DBASE III+  DBF files.
  5223.  
  5224.     However, I  have chosen  not to  go into  detail on  index files.  I'll
  5225.  
  5226.     leave that to a future version of PSK.
  5227.  
  5228.  
  5229.  
  5230.     A DBASE III+ DBF file is  used to store database records. This  file is
  5231.  
  5232.     divided into several areas  as illustrated. The header  contains global
  5233.  
  5234.     information  about this  file  including  the  date  when  it  was last
  5235.  
  5236.     updated  and the  number  of  records.  The  data dictionary  describes
  5237.  
  5238.     every field that  is part of  the record. A  carriage return (CR)  byte
  5239.  
  5240.     ends the  data dictionary.  Records contain  the actual  data. A CTRL-Z
  5241.  
  5242.     byte  marks the  end  of  the  file.  Each  record  is  preceded  by an
  5243.  
  5244.     asterisk byte  if it  has been  marked for  deletion otherwise  a blank
  5245.  
  5246.     (ASCII 20h) byte appears.
  5247.  
  5248.  
  5249.  
  5250.     ┌────────────┐
  5251.  
  5252.     │ HEADER     │
  5253.  
  5254.     ├────────────┤
  5255.  
  5256.     │ DATA       │
  5257.  
  5258.     │ DICTIONARY │
  5259.  
  5260.     ├────────────┤
  5261.  
  5262.     │     CR     │
  5263.  
  5264.     ├────────────┤
  5265.  
  5266.     │ RECORDS    │
  5267.  
  5268.     ├────────────┤
  5269.  
  5270.     │   CTRL-Z   │
  5271.  
  5272.     └────────────┘
  5273.  
  5274.  
  5275.  
  5276.  
  5277.  
  5278.                               -1Header Organization-0
  5279.  
  5280.  
  5281.  
  5282.  
  5283.  
  5284.     Byte     0  Version Number
  5285.  
  5286.  
  5287.  
  5288.     This  byte holds  03h  if  no  DBT  (memo) file  is present  or 83h  if
  5289.  
  5290.     present.
  5291.  
  5292.  
  5293.  
  5294.     Byte  1- 3  Last Update
  5295.  
  5296.  
  5297.  
  5298.     These three bytes hold the date  when the file was last updated  in YY,
  5299.  
  5300.     MM, DD order. The YY  component is calculated by subtracting  1900 from
  5301.  
  5302.     the current year.
  5303.  
  5304.  
  5305.  
  5306.     Byte  4- 7  Header Length
  5307.  
  5308.  
  5309.  
  5310.     The number of bytes  taken up by the  header plus the data  dictionary,
  5311.  
  5312.     and the trailing CR byte is stored here.
  5313.  
  5314.  
  5315.  
  5316.     Byte 10-11  Record Length
  5317.  
  5318.  
  5319.  
  5320.     The length of  a record (including  the byte that  immediately precedes
  5321.  
  5322.     the record and indicates whether or not the record has been marked  for
  5323.  
  5324.     deletion) is stored here.
  5325.  
  5326.  
  5327.  
  5328.     Byte 12-31  Reserved
  5329.  
  5330.  
  5331.  
  5332.  
  5333.                                     - 43 -
  5334.  
  5335.  
  5336.  
  5337.  
  5338.                          -1Data Dictionary Organization-0
  5339.  
  5340.  
  5341.  
  5342.  
  5343.  
  5344.     Each entry in the data dictionary  describes one field that makes up  a
  5345.  
  5346.     record  and is  exactly  32  bytes  in  length. Upto  a maximum  of 128
  5347.  
  5348.     entries can be recorded in  the dictionary. The following byte  offsets
  5349.  
  5350.     are relative to the start of an entry.
  5351.  
  5352.  
  5353.  
  5354.     Byte  0-10  Field Name
  5355.  
  5356.  
  5357.  
  5358.     The field name consists of ASCII characters and is left-justified  with
  5359.  
  5360.     NULL (ASCII 0) bytes padded to the right.
  5361.  
  5362.  
  5363.  
  5364.     Byte 11     Field Type
  5365.  
  5366.  
  5367.  
  5368.     The field type is an ASCII  character describing the kind of data  that
  5369.  
  5370.     can be stored.
  5371.  
  5372.  
  5373.  
  5374.     C (character) ASCII characters
  5375.  
  5376.     N (numeric)   - . 0 1 2 3 4 5 6 7 8 9
  5377.  
  5378.     L (logical)   Y y N n T t F f (contains ? when not initialized)
  5379.  
  5380.     M (memo)      10 digits representing a DBT block number
  5381.  
  5382.     D (date)      8 digits in YYYYMMDD format
  5383.  
  5384.  
  5385.  
  5386.     Byte 12-15  Reserved
  5387.  
  5388.  
  5389.  
  5390.     Should be set to 0.
  5391.  
  5392.  
  5393.  
  5394.     Byte 16     Field Length
  5395.  
  5396.  
  5397.  
  5398.     The length ranges from 0 to 255.
  5399.  
  5400.  
  5401.  
  5402.     Byte 17     Field Decimal Count
  5403.  
  5404.  
  5405.  
  5406.     The number of digits after the decimal point.
  5407.  
  5408.  
  5409.  
  5410.     Byte 18-31  Reserved
  5411.  
  5412.  
  5413.  
  5414.     Should be set to 0.
  5415.  
  5416.  
  5417.  
  5418.     A  memo is  a  variable-length  character string.  The actual  data for
  5419.  
  5420.     each memo  is kept  in a  separate file  with the  same name as the DBF
  5421.  
  5422.     file but with a  DBT extension. I do  not know the DBT  file format and
  5423.  
  5424.     am only guessing at the block  number but the 10 digits would  be ASCII
  5425.  
  5426.     digits  and   probably  serve   as  an   index  into   the  DBT   file.
  5427.  
  5428.  
  5429.  
  5430.  
  5431.  
  5432.                                   -1Limitations-0
  5433.  
  5434.  
  5435.  
  5436.  
  5437.  
  5438.     1 billion records maximum
  5439.  
  5440.     4000 bytes per record maximum
  5441.  
  5442.     128 fields per record maximum
  5443.  
  5444.     254 bytes per character field maximum (trailing blanks)
  5445.  
  5446.     1 byte per logical field (exactly)
  5447.  
  5448.     19 bytes per numeric field maximum
  5449.  
  5450.     8 bytes per date field (exactly)
  5451.  
  5452.     10 memo fields maximum
  5453.  
  5454.  
  5455.  
  5456.  
  5457.                                     - 44 -
  5458.  
  5459.  
  5460.  
  5461.  
  5462.                              -1Appendix C ■ MAKEDRV-0
  5463.  
  5464.  
  5465.  
  5466.  
  5467.  
  5468.     MAKEDRV  is a  program  that  I invented  to make  it easier  to create
  5469.  
  5470.     printer  driver files.  A  driver  has a  DRV extension.  When I  first
  5471.  
  5472.     came up with the concept of  drivers, I did not realize that  Microsoft
  5473.  
  5474.     Windows uses  DRV as  a file  extension for  its drivers. Therefore, be
  5475.  
  5476.     warned in advance  that you should  not mix PSK  drivers with Microsoft
  5477.  
  5478.     Windows drivers.
  5479.  
  5480.  
  5481.  
  5482.     The function  of a  driver is  simple. The  application program sends a
  5483.  
  5484.     virtual printer string  to the print  manager. The print  manager looks
  5485.  
  5486.     up this string in  the currently loaded driver.  If there is no  loaded
  5487.  
  5488.     driver then the  manager sends the  string verbatim to  the printer. If
  5489.  
  5490.     there is a loaded driver and  the virtual string is not found  then the
  5491.  
  5492.     manager discards  the string.  It is  not sent  to the  printer. If the
  5493.  
  5494.     string is found then  the real printer string  which is also stored  in
  5495.  
  5496.     the  driver is  sent  to  the printer  instead of  the virtual  string.
  5497.  
  5498.  
  5499.  
  5500.     A  virtual string  starts  with  an  ESC  character (ASCII  27). It  is
  5501.  
  5502.     terminated by a  # character. For  example, the following  is a virtual
  5503.  
  5504.     string: ^27A#. The ^27  is interpreted as a  control code (ESC in  this
  5505.  
  5506.     case). The A  serves as an  ID code for  this string. The  # terminates
  5507.  
  5508.     the string.
  5509.  
  5510.  
  5511.  
  5512.     DMP130  and HPLJIII  contain  the  source  code  for sample  drivers. A
  5513.  
  5514.     driver is  divided into  one or  more lines.  The maximum  length of  a
  5515.  
  5516.     line  is 127  characters. Blank  lines can  be entered.  A comment  can
  5517.  
  5518.     appear  anywhere. Comments  start  with  semicolons and  all characters
  5519.  
  5520.     following a semicolon to the end  of the line are ignored. The  keyword
  5521.  
  5522.     VIRTUAL is used to indicate the  start of a virtual string and  must be
  5523.  
  5524.     placed on a line by itself.  The keyword REAL indicates the start  of a
  5525.  
  5526.     real string and  also must appear  by itself. Following  either keyword
  5527.  
  5528.     is a set of codes on a  separate line. Unsigned integers from 0 to  255
  5529.  
  5530.     can be entered as well  as strings of ASCII characters  located between
  5531.  
  5532.     a pair of double  quotation marks. Each string  can appear on only  one
  5533.  
  5534.     line.
  5535.  
  5536.  
  5537.  
  5538.     Some  rules need  to  be  followed  when  writing  a  source file.  The
  5539.  
  5540.     maximum length of a virtual string including the leading ESC  character
  5541.  
  5542.     is 40 bytes. A virtual string  can never include a # character  as part
  5543.  
  5544.     of the string since this  character is recognized by the  print manager
  5545.  
  5546.     as  a terminator.  Therefore,  you  would never  include a  # character
  5547.  
  5548.     with  the other  characters  forming  a  virtual  string.  The  maximum
  5549.  
  5550.     number of virtual strings is 32  and real strings is 32. The  number of
  5551.  
  5552.     virtual strings  must equal  the number  of real  strings. The  maximum
  5553.  
  5554.     size of  a DRV  file is  1024 bytes  and the  minimum size is 16 bytes.
  5555.  
  5556.     
  5557.  
  5558.     MAKEDRV is easy to use.  The syntax is -1MAKEDRV filespec-0  where filespec
  5559.  
  5560.     identifies the source file  to be converted into  a DRV file. The  file
  5561.  
  5562.     is listed  line by  line to  the STDOUT  device and  error messages are
  5563.  
  5564.     sent  to the  STDERR  device.  MAKEDRV  requires  DOS  3.30  or higher.
  5565.  
  5566.  
  5567.  
  5568.  
  5569.  
  5570.  
  5571.  
  5572.  
  5573.  
  5574.  
  5575.  
  5576.  
  5577.  
  5578.  
  5579.  
  5580.  
  5581.                                     - 45 -
  5582.  
  5583.  
  5584.  
  5585.  
  5586.                          -1Appendix D ■ Sample Programs-0
  5587.  
  5588.  
  5589.  
  5590.  
  5591.  
  5592.     Five example programs  are included with  the PSK library  illustrating
  5593.  
  5594.     the various functions.  By studying the  source code for  each example,
  5595.  
  5596.     you should get a  good idea of how  to put these functions  together to
  5597.  
  5598.     build useful programs.
  5599.  
  5600.  
  5601.  
  5602.     The first program is a database program called Employee Absence  Record
  5603.  
  5604.     (EAR). EAR is used  to keep track of  the number of days  each employee
  5605.  
  5606.     in a company is absent for  each quarter of a year for  different years
  5607.  
  5608.     between 1990 and 2050  inclusive. If you have  an EGA adaptor, you  can
  5609.  
  5610.     run this  program in  43-line mode  by typing  "EAR 43".  If you have a
  5611.  
  5612.     VGA/SVGA adaptor, you  can run this  program in 50-line  mode by typing
  5613.  
  5614.     "EAR   50".    EAR   requires    DOS   3.30    or   higher    to   run.
  5615.  
  5616.  
  5617.  
  5618.     If  you are  interested  in  seeing  how  the  critical  error  handler
  5619.  
  5620.     functions, copy  EAR.EXE and  one of  the DRV  files to  a floppy disk.
  5621.  
  5622.     Insert the disk  into one of  the floppy drives  and then log  onto the
  5623.  
  5624.     drive (make that drive current). Open  the door handle and try to  load
  5625.  
  5626.     a  file. Press  F1  to  see  the  help screen  once the  critical error
  5627.  
  5628.     handler appears.
  5629.  
  5630.  
  5631.  
  5632.     The  scrolling logic  is the  most complex  code in  this program.  EAR
  5633.  
  5634.     displays a window in the middle  of the screen. This window is  used to
  5635.  
  5636.     display employee names.  EAR can support  upto 256 employees  and hence
  5637.  
  5638.     display 256  employee names  but not  all names  can appear within this
  5639.  
  5640.     window at any  one time. Therefore,  some means of  scrolling is needed
  5641.  
  5642.     to make it possible to view  all names. The scrolling logic has  turned
  5643.  
  5644.     out to be the hardest part of the program to write because of the  need
  5645.  
  5646.     to track the  lightbar to the  appropriate location after  inserting or
  5647.  
  5648.     deleting an  employee. For  example, suppose  you are  deleting several
  5649.  
  5650.     names near the end of the  list. Once the first name has  been deleted,
  5651.  
  5652.     the name  of the  employee that  follows will  be highlighted.  You can
  5653.  
  5654.     keep  pressing DEL  until  all  desired  employees  have been  deleted.
  5655.  
  5656.     Similarly, when  inserting employee  names, the  lightbar jumps  to the
  5657.  
  5658.     next  insert position  so  you  can insert  names one  right after  the
  5659.  
  5660.     other.
  5661.  
  5662.  
  5663.  
  5664.     The  second program,  called  EDEMO,  provides a  demonstration of  the
  5665.  
  5666.     event handler  mechanism. You  may wish  to elaborate  on this code and
  5667.  
  5668.     turn EDEMO into something more useful.
  5669.  
  5670.  
  5671.  
  5672.     The third program  is called FILES  and lets you  play with DOS  files.
  5673.  
  5674.     You  can scroll  through a  list of  files, sort  them in  alphabetical
  5675.  
  5676.     order, rename  files, change  directories, etc.  FILES provides  a good
  5677.  
  5678.     example of the dialog  box function. You can  run FILES in EGA  43-line
  5679.  
  5680.     mode by typing "FILES 43" or in VGA 50-line mode by typing "FILES  50".
  5681.  
  5682.     Of  course, you  need  an  appropriate  video  adaptor. FILES  uses the
  5683.  
  5684.     streamlined critical  error handler.  If a  critical error  occurs, you
  5685.  
  5686.     will only see a dialog box telling you that a certain action cannot  be
  5687.  
  5688.     performed.
  5689.  
  5690.  
  5691.  
  5692.     The fourth program  is called JOYDEMO  and plays a  medly of background
  5693.  
  5694.     music pieces while  scanning the joystick  position and button  status.
  5695.  
  5696.     I had planned to write a game to illustrate these features but ran  out
  5697.  
  5698.     of  time. Perhaps,  the  next  version  of  PSK will  show something  a
  5699.  
  5700.     little more interesting.
  5701.  
  5702.  
  5703.  
  5704.  
  5705.                                     - 46 -
  5706.  
  5707.  
  5708.  
  5709.  
  5710.     The final program is called SQ  and uses the system query functions  to
  5711.  
  5712.     find  out certain  things  about  your  computer.  If you  have Windows
  5713.  
  5714.     capability, try running  Windows in standard  or 386-enhanced mode  and
  5715.  
  5716.     shell out to  DOS via the  MSDOS ICON in  the MAIN group.  What happens
  5717.  
  5718.     when you run SQ?
  5719.  
  5720.  
  5721.  
  5722.  
  5723.  
  5724.  
  5725.  
  5726.  
  5727.  
  5728.  
  5729.  
  5730.  
  5731.  
  5732.  
  5733.  
  5734.  
  5735.  
  5736.  
  5737.  
  5738.  
  5739.  
  5740.  
  5741.  
  5742.  
  5743.  
  5744.  
  5745.  
  5746.  
  5747.  
  5748.  
  5749.  
  5750.  
  5751.  
  5752.  
  5753.  
  5754.  
  5755.  
  5756.  
  5757.  
  5758.  
  5759.  
  5760.  
  5761.  
  5762.  
  5763.  
  5764.  
  5765.  
  5766.  
  5767.  
  5768.  
  5769.  
  5770.  
  5771.  
  5772.  
  5773.  
  5774.  
  5775.  
  5776.  
  5777.  
  5778.  
  5779.  
  5780.  
  5781.  
  5782.  
  5783.  
  5784.  
  5785.  
  5786.  
  5787.  
  5788.  
  5789.  
  5790.  
  5791.  
  5792.  
  5793.  
  5794.  
  5795.  
  5796.  
  5797.  
  5798.  
  5799.  
  5800.  
  5801.  
  5802.  
  5803.  
  5804.  
  5805.  
  5806.  
  5807.  
  5808.  
  5809.  
  5810.  
  5811.  
  5812.  
  5813.  
  5814.  
  5815.  
  5816.  
  5817.  
  5818.  
  5819.  
  5820.  
  5821.  
  5822.  
  5823.  
  5824.  
  5825.  
  5826.  
  5827.  
  5828.  
  5829.                                     - 47 -
  5830.  
  5831.  
  5832.  
  5833.  
  5834.                            -1Appendix E ■ Installation-0
  5835.  
  5836.  
  5837.  
  5838.  
  5839.  
  5840.     PSK is  distributed in  archived form  as PSK.ZIP.  The following files
  5841.  
  5842.     are located in this archive.
  5843.  
  5844.  
  5845.  
  5846.     README      - special instructions on printing PSK.DOC file
  5847.  
  5848.     PSK.DOC     - documentation
  5849.  
  5850.     PSK.REG     - registration information
  5851.  
  5852.     CEH.H       - Critical Error Handler header file
  5853.  
  5854.     CLASSCVT.H  - Classifications and Conversions header file
  5855.  
  5856.     DATETIME.H  - Date & Time Tools header file
  5857.  
  5858.     DIALOG.H    - Dialog Box header file
  5859.  
  5860.     EDIT.H      - Data Entry Editor header file
  5861.  
  5862.     EVENT.H     - Event Handler header file
  5863.  
  5864.     FD.H        - File & Directory header file
  5865.  
  5866.     GAME.H      - Game Tools header file
  5867.  
  5868.     KBD.H       - Keyboard Interface/Context Sensitive Help header file
  5869.  
  5870.     MACROS.H    - Useful Macros
  5871.  
  5872.     MOUSE.H     - Mouse Driver Interface header file
  5873.  
  5874.     MSG.H       - Message Box header file
  5875.  
  5876.     PRINT.H     - Printer Interface header file
  5877.  
  5878.     PSK.H       - PSK Identification header file
  5879.  
  5880.     SECURITY.H  - File Security header file
  5881.  
  5882.     SQ.H        - System Query header file
  5883.  
  5884.     STR.H       - String Management header file
  5885.  
  5886.     VIDEO.H     - Video Interface header file
  5887.  
  5888.     PSK.LIB     - LARGE model version of the PSK C library
  5889.  
  5890.     EAR.C       - Employee Absence Record source file 
  5891.  
  5892.     EAR.PRJ     - Employee Absence Record project file
  5893.  
  5894.     EAR.EXE     - Employee Absence Record executable file
  5895.  
  5896.     EDEMO.C     - Event Handler Demonstration source file
  5897.  
  5898.     EDEMO.PRJ   - Event Handler Demonstration project file
  5899.  
  5900.     EDEMO.EXE   - Event Handler Demonstration executable file
  5901.  
  5902.     FILES.C     - DOS Files Tool source file
  5903.  
  5904.     FILES.PRJ   - DOS Files Tool project file
  5905.  
  5906.     FILES.EXE   - DOS Files Tool executable file
  5907.  
  5908.     JOYDEMO.C   - Joystick/Background Music Demonstration source file
  5909.  
  5910.     JOYDEMO.PRJ - Joystick/Background Music Demonstration project file
  5911.  
  5912.     JOYDEMO.EXE - Joystick/Background Music Demonstration executable file
  5913.  
  5914.     SQ.C        - System Query Demonstration source file
  5915.  
  5916.     SQ.PRJ      - System Query Demonstration project file
  5917.  
  5918.     SQ.EXE      - System Query Demonstration executable file
  5919.  
  5920.     MAKEDRV.EXE - MAKEDRV utility program
  5921.  
  5922.     DMP130      - source code for Tandy DMP 130 printer driver
  5923.  
  5924.     HPLJIII     - source code for HP Laserjet III printer driver
  5925.  
  5926.     DMP130.DRV  - DMP 130 driver
  5927.  
  5928.     HPLJIII.DRV - Laserjet driver
  5929.  
  5930.  
  5931.  
  5932.     Installation is fairly straightforward.  The simplest install would  be
  5933.  
  5934.     to copy the .H files into your INCLUDE directory and PSK.LIB into  your
  5935.  
  5936.     LIB directory.  You could  also make  a separate  directory called  PSK
  5937.  
  5938.     and  copy these  files  into  that directory.  You would  then need  to
  5939.  
  5940.     setup  your INCLUDE  and  LIB  paths to  point to  this directory.  You
  5941.  
  5942.     might need to change the project files.
  5943.  
  5944.  
  5945.  
  5946.  
  5947.  
  5948.                                     - 48 -